使 shared_ptr 失去内存所有权

Making shared_ptr lose ownership of memory

我有一个shared_ptr<MyProto>,我传了过来。最终,在某些情况下,我想将原始指针传递给一个函数,然后该函数成为内存所有者。在那些情况下,shared_ptr 不再负责释放内存,因为我调用的函数获得了所有权。如何让 shared_ptr 失去所有权?

我想让 shared_ptr 失去所有权的原因是我想使用协议缓冲区的 AddAllocated 功能,它接受一个已经分配的指针并获得它的所有权。

示例:

shared_ptr<MyProto> myProtoSharedPtr = // by this point this is the last reference to the heap allocated MyProto

// I want to add it to a collection and serialize the collection without copying
CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedPtr.get()); // at this point collectionProto took ownership of the memory
std::string serialization = collectionProto.SerializeAsString();

// bad: myProtoSharedPtr.get() will be freed twice

您可以使用 unique_ptr,它无论如何更适合传递内存:

unique_ptr<MyProto> myProtoSharedPtr = // create MyPorto object

CollectionProto collectionProto;

// unique_ptr::release returns the pointer and
// releases the ownership of the MyProto object
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedPtr.release());

std::string serialization = collectionProto.SerializeAsString();

您需要为 std::shared_ptr 提供 custom deleter(参见构造函数 4)。然后你可以定义删除器来做你想做的事。包括,不破坏你的对象。

注意 1:我不推荐在这里使用 shared_ptr,但这是一种做你想做的方式。

注意 2:如果您使用 make_shared 创建您的对象,您可能会 运行 在删除最后一个 shared_ptr 后正确删除内存。

我认为你可以通过分享一个独特的方式来实现你想做的事情 指针 像这样:

std::shared_ptr<std::unique_ptr<MyProto>> myProtoSharedUniquePtr;

访问它会更间接:

(*myProtoSharedUniquePtr)->do_stuff();

但您可以这样取得所有权:

CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedUniquePtr->release()); // at this point collectionProto took ownership of the memory
std::string serialization = collectionProto.SerializeAsString();

但是我会质疑您为什么使用 std::shared_ptr 作为开头。使用 std::shared_ptr 的原因是当您无法控制谁将最后访问它时,因此每个人都可以在完成之前保持它的活动状态。因此,能够保证所有当前 std::shared_ptr 实例不再使用是不寻常的。

您确定 std::unique_ptr 不会更好地满足您的需求吗?

当你想转移所有权时,你可以使用std::move,见下面的例子

#include <iostream>
#include <memory>
void take_ownership(std::shared_ptr<int> ptr){
std::cout<<ptr.use_count()<<" == 2\n";
} // destroying it


int main()
{
std::shared_ptr<int> p=std::make_shared<int>(1);
std::shared_ptr<int> p2(p);
//p is valid                                                                                                                                                                                                                                                                              
if(!p.get())
std::cout<<"error\n";
else
std::cout<<"OK\n";

//use p, p2

take_ownership(std::move(p));
//p is invalid                                                                                                                                                                                                                                                                            
if(!p.get())
std::cout<<"OK\n";
else
std::cout<<p.use_count()<<" error\n";

}

您可以将其移动到 newed 对象中,而不是复制。

MyProto * myProto = new MyProto(std::move(*mySharedProto));

CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProto);

您还可以调查 CollectionProto 是否会按值接受它

CollectionProto collectionProto;
collectionProto.mutable_my_proto().Add(std::move(*mySharedProto));