我想重置一个shared_ptr
而不删除它的对象,让它的weak_ptr
失去对它的引用。但是,由于某些原因,shared_ptr
没有release((成员函数,所以我不能直接执行。最简单的解决方案是调用weak_ptr
的reset((,但拥有shared_ptr
并想要释放它的类不知道哪个类有weak_ptr
。在这种情况下如何做到这一点?
我理解为什么shared_ptr
没有发布功能而只有unique_ptr
。在我的情况下,只有一个实例拥有一个指针,但shared_ptr
可以由多个实例拥有,因此释放是没有意义的。但是,如果shared_ptr
没有这个功能,我如何在不删除对象的情况下切断与weak_ptr
的连接?
shared_ptr<int> A = make_shared<int>(100);
weak_ptr<int> B = A;
// I want something like this! but shared_ptr doesn't have release function..
int* releasedData = A.release();
A.reset(releasedData);
if (shared_ptr<int> C = B.lock)
{
// B already lost a reference, so it should never reach here
}
背景
存储大数组指针的类的共享指针与其他类共享。共享指针作为指向这些类的弱指针传递,共享指针的所有者类不知道这些类。所有者类的多个实例在运行时被激活和停用。由于实例的初始化成本很高,我使用对象池模式:我重用这些实例,而不是每次使用它时都创建/删除。这里的问题是,当所有者类的实例被停用时,它应该被视为已删除(尽管它仍然保存数据(,因此其他对数据引用较弱的类应该失去引用。重置共享指针是可能的,但我不想这样做,因为数据很大。
我可以创建一个管理器类来跟踪哪个弱指针指向哪个共享指针,但我想知道这是否可以通过其他方法解决。
std::shared_ptr
和std::weak_ptr
用于对RAII的概念进行建模。当您使用std::shared_ptr
时,您已经决定它拥有资源,并且应该在销毁时释放资源。你面临的笨拙是由于对RAII的反叛:你希望std::shared_ptr
拥有资源,但有时并不是真的。
解决方案是将对象池重新定义为分配器。假设你有
struct obj_t { /* ... */ };
struct pool_t {
obj_t* acquire(); // get an object from the pool
void release(obj_t*); // return the object to the pool
// ...
};
然后你的std::shared_ptr
将看起来像
auto d = [&pool](auto p){ pool.release(p); };
std::shared_ptr<obj_t> obj{pool.acquire(), d};
值得注意的是,资源获取总是与其销毁配对。在这种模式下,你的问题不存在
std::weak_ptr<obj_t> b = obj;
obj = nullptr; // or let obj get destroyed in any other way
if(auto c = b.lock())
// doesn't happen
您可以使用带有自定义deleter的shared_ptr
来防止对象被破坏:
shared_ptr<int> A = shared_ptr<int>(new int(100), [](int*){});
weak_ptr<int> B = A;
// Save the pointer that you otherwise would lose:
int* releasedData = A.get();
A = shared_ptr<int>(releasedData, [](int*){});;
if (shared_ptr<int> C = B.lock())
{
// B already lost a reference, so it should never reach here
}
但是不要忘记通过任何其他方式删除对象。例如:
shared_ptr<int> realOwner(new int(100));
shared_ptr<int> A = shared_ptr<int>(realOwner.get(), [](int*){});
weak_ptr<int> B = A;