问题
I have a shared_ptr<MyProto>
which I pass around. Eventually, in certain situations, I want pass the raw pointer to a function which then becomes the memory owner. In those cases the shared_ptr
isn't responsible anymore for freeing the memory because the function I call took ownership. How do I get the shared_ptr
to lose ownership?
The reason I want to have the shared_ptr
lose ownership is that I want to use protocol buffer's AddAllocated functionality which takes an already allocated pointer and assumes ownership of it.
Example:
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
回答1:
I think you can achieve what you want to do by sharing a unique pointer like this:
std::shared_ptr<std::unique_ptr<MyProto>> myProtoSharedUniquePtr;
Accessing it would be more indirect:
(*myProtoSharedUniquePtr)->do_stuff();
But you could take ownership like this:
CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProtoSharedUniquePtr->release()); // at this point collectionProto took ownership of the memory
std::string serialization = collectionProto.SerializeAsString();
However I would question why you are using a std::shared_ptr
to begin with. The reason to use a std::shared_ptr
is when you have no control over who will be last to access it, so each one gets to keep it alive until they are done. So it would be unusual to be able to guarantee all current std::shared_ptr
instances are no longer in use.
Are you sure a std::unique_ptr
would not be better for your needs?
回答2:
You could use a unique_ptr
, which is anyhow better suited for passing memory around:
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();
回答3:
You will need to provide std::shared_ptr
with a custom deleter (See constructor 4). Then you can define the deleter to do what you want. Including, not destroy your object.
Note 1: I don't recomend using shared_ptr here, but this is a way to do what you want.
Note 2: If you use make_shared
to create your objects you will likely run into trouble correctly deleting the memory once the last shared_ptr is removed.
回答4:
Rather than copying, you could move it into a new
ed object.
MyProto * myProto = new MyProto(std::move(*mySharedProto));
CollectionProto collectionProto;
collectionProto.mutable_my_proto().AddAllocated(myProto);
You could also investigate whether CollectionProto
will accept it by value
CollectionProto collectionProto;
collectionProto.mutable_my_proto().Add(std::move(*mySharedProto));
回答5:
You could use std::move when you want to transfer the ownership, see the following example
#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";
}
来源:https://stackoverflow.com/questions/50831775/making-shared-ptr-lose-ownership-of-memory