我需要将原始指针包装成 ashared_ptr
以便将其传递给函数。该函数一旦返回就不会持有对输入对象的任何引用。
{
MyClass i;
shared_ptr<MyClass> p(&i);
f(p);
// BAD: shared_ptr will delete i.
}
如何防止shared_ptr
删除引用的对象?
我需要将原始指针包装成 ashared_ptr
以便将其传递给函数。该函数一旦返回就不会持有对输入对象的任何引用。
{
MyClass i;
shared_ptr<MyClass> p(&i);
f(p);
// BAD: shared_ptr will delete i.
}
如何防止shared_ptr
删除引用的对象?
正如克里斯在评论中提到的那样,写一个空的删除器:
#include <type_traits>
template <typename T>
struct empty_delete
{
empty_delete() /* noexcept */
{
}
template <typename U>
empty_delete(const empty_delete<U>&,
typename std::enable_if<
std::is_convertible<U*, T*>::value
>::type* = nullptr) /* noexcept */
{
}
void operator()(T* const) const /* noexcept */
{
// do nothing
}
};
使用示例:
#include <iostream>
#include <memory>
struct noisy
{
noisy() { std::cout << "alive" << std::endl; }
~noisy() { std::cout << "dead" << std::endl; }
noisy(const noisy&);
noisy& operator=(const noisy&);
};
template <typename T>
void take(T& yours)
{
std::cout << "Taking..." << std::endl;
{
auto mine = std::move(yours);
}
std::cout << "Took." << std::endl;
}
int main()
{
std::unique_ptr<noisy> a(new noisy());
std::shared_ptr<noisy> b(new noisy());
std::unique_ptr<noisy, empty_delete<noisy>> c(new noisy());
std::shared_ptr<noisy> d(new noisy(), empty_delete<noisy>());
take(a);
take(b);
take(c);
take(d);
}
输出:
活着
活着
活着
活着
采取...
死了 采取
了。
采取...
死
了。
采取...采取
。
采取...采取
。
当然,这个例子会泄漏内存。
对于评论中提到的 .NET/clr,您应该实现ref class
、传递托管句柄^
并让垃圾收集器管理生命周期。
ref class MyClassManaged : public Pen
{
public:
MyClassManaged() : Pen{}, native_{ new MyClass{} } { }
~MyClassManaged() { this->!MyClassManaged(); }
!MyClassManaged() { delete native_; }
private:
MyClass* native_;
};
//...
{
MyClassManaged^ i = gcnew MyClassManaged{};
fManaged(i);
}
TL;DR 只需保留另一个活动副本,如果您仍然需要它,则在堆而不是堆栈上shared_ptr<MyClass>
分配。i
方案 1
{
shared_ptr<MyClass> another_p;
{
MyClass i;
shared_ptr<MyClass> p(&i);
f(p);
// p has not deleted i yet
another_p = p; // increment reference count
// p will decrement the reference count
// i will be deleted due to stack unwinding
}
// another_p still holds a reference to where i was on the stack
if (another_p)
something(); // yes, something() will be invoked
else
nothing(); // no, nothing() won't run here
// another_p will attempt to delete again if not the shared_ptr is not copied elsewhere
}
方案 2
{
shared_ptr<MyClass> another_p;
{
auto p = make_shared<MyClass>();
auto& i = *p;
f(p);
// p has not deleted i
another_p = p; // increment reference count
// p will decrement the reference count
// i will be NOT deleted
}
// another_p still holds a reference to where i was on the heap
if (another_p)
something(); // yes, something() will be invoked
else
nothing(); // no, nothing() won't run here
// another_p will attempt to delete again if not the shared_ptr is not copied elsewhere
}
// it will finally be deleted now
只需保留 shared_ptr 的另一个副本;无需像空的删除器一样弄乱。