Making shared_ptr lose ownership of memory - c++

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

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?

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();

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.

Rather than copying, you could move it into a newed 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));

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";
}

Related

Scalar deleting error when deleting std::shared_ptr

I am trying to find out how can I delete children of my Block class. I tried to do it with raw pointer. I don't know why, but it didn't work. I was getting the scalar deleting error. I now tried to do this with std::shared_ptr. I t didn't work as well. I am removing the children with:
void Block::remove(Block* block)
{
std::shared_ptr<Block> ptr(block);
auto it = std::find(children.begin(), children.end(), ptr);
if (it != children.end())
{
*it = NULL;
children.erase(it);
}
}
and the Block deleter is:
Block::~Block()
{
for (auto& child : this->children)
{
child = NULL;
}
if (!this->children.empty())
this->children.clear();
}
According to the debugging process, the ptr variable is found and then deleted. At the point of deleting everything works well until the last line, where I am getting the scalar deletion error. Just for the record: the children variable is of type std::vector<std::shared_ptr<Block>>.
EDIT:
The full code is here: https://github.com/DragonGamesStudios/Ages-of-Life. All the block functions are defined in AOLGuiLibrary/source/Block.cpp
You are mixing shared_ptrs with raw pointers, and that is a bad practice. If I understand correctly, you store the blocks in the vector of shared pointers, and that means that this vector has an ownership on these objects. When you create an additional shared_ptr out of a raw pointer you create another object that has the ownership on the same object:
std::shared_ptr<Block> ptr(block);
As the result, you would try to delete the object twice, and that leads to the undefined behavior.
First of all: do you need shared pointers? Consider using unique_ptr as a less error prone idea (if only one pointer object has the ownership, it is easier to understand who and when would destroy the underlying object).
Next, NEVER use raw pointers in this context: you may use raw pointers only when you don't store/delete the object. And for sure don't create smart pointers out of something that is already stored in one of them already.
Once a pointer has been given to a shared_ptr, that shared_ptr owns it. You must never again give that pointer to another shared pointer.
int * ptr = new int(1234);
{
std::shared_ptr<int> shp1(ptr); // shp1 owns ptr
std::shared_ptr<int> shp2(ptr); // shp2 owns ptr ???
}
// at this point ptr has been deleted twice
Note: it's preferable to not use new but to call std::make_shared and never give raw pointers to shared_ptr in the first place.
What you are doing to search for a child is exactly this problem. Passing in a raw pointer, you create a new owner for it. If that pointer is a child, it's already owned. You must not create shared pointers from raw pointers after they have been given to a shared pointer.
Also, the destructor you showed for Block isn't wrong, but it is completely unnecessary. All of what you coded there would happen automatically. Block is destroyed, it destroys the vector it holds (so clearing it is unnecessary.) The vector destroys its elements, so the shared pointers it holds are cleaned up too.
If block points at array code, this code is illegal, because for a new[] you have to call delete[], and std::shared_ptr<Block> would call delete. After that heap would be corrupted and further operations may fail. Same happens if blocks points to an element of array. If blocks points to object not located in heap, it also would result in error.
In general it's bad idea to delete a pointer passed to a function. There is no guarantee that the pointer was one returned by new, and even if it was: by which new?
To create a strong reference counter for an array, you have to use std::shared_ptr<Block[]>, but usually it's better idea to use some kind of container.
To find a value of pointer object in array of shared pointers:
auto it = std::find_if( children.begin(), children.end(), [=](auto& el) {
return el.get() == block;
});
If childrenis not static (that's not some kind of factory), then that destructor code is completely redundant. After call to ~Block() there will be calls to destructors of every member of Block, including that collection which would deallocate its resources and call destructor to every pointer, which would call destructor to every Block.

C++ multiple unique pointers from same raw pointer

Consider my code below. My understanding of unique pointers was that only one unique pointer can be used to reference one variable or object. In my code I have more than one unique_ptr accessing the same variable.
It's obviously not the correct way to use smart pointers i know, in that the pointer should have complete ownership from creation. But still, why is this valid and not having a compilation error? Thanks.
#include <iostream>
#include <memory>
using namespace std;
int main()
{
int val = 0;
int* valPtr = &val;
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(valPtr);
*uniquePtr1 = 10;
*uniquePtr2 = 20;
return 0;
}
But still, why is this valid
It is not valid! It's undefined behaviour, because the destructor of std::unique_ptr will free an object with automatic storage duration.
Practically, your program tries to destroy the int object three times. First through uniquePtr2, then through uniquePtr1, and then through val itself.
and not having a compilation error?
Because such errors are not generally detectable at compile time:
unique_ptr <int> uniquePtr1(valPtr);
unique_ptr <int> uniquePtr2(function_with_runtime_input());
In this example, function_with_runtime_input() may perform a lot of complicated runtime operations which eventually return a pointer to the same object valPtr points to.
If you use std::unique_ptr correctly, then you will almost always use std::make_unique, which prevents such errors.
Just an addition to Christian Hackl's excellent answer:
std::unique_ptr was introduced to ensure RAII for pointers; this means, in opposite to raw pointers you don't have to take care about destruction yourself anymore. The whole management of the raw pointer is done by the smart pointer. Leaks caused by a forgotten delete can not happen anymore.
If a std::unique_ptr would only allow to be created by std::make_unique, it would be absolutely safe regarding allocation and deallocation, and of course that would be also detectable during compile time.
But that's not the case: std::unique_ptr is also constructible with a raw pointer. The reason is, that being able to be constructed with a hard pointer makes a std::unique_ptr much more useful. If this would not be possible, e.g. the pointer returned by Christian Hackl's function_with_runtime_input() would not be possible to integrate into a modern RAII environment, you would have to take care of destruction yourself.
Of course the downside with this is that errors like yours can happen: To forget destruction is not possible with std::unique_ptr, but erroneous multiple destructions are always possible (and impossible to track by the compiler, as C.H. already said), if you created it with a raw pointer constructor argument. Always be aware that std::unique_ptr logically takes "ownership" of the raw pointer - what means, that no one else may delete the pointer except the one std::unique_ptr itself.
As rules of thumb it can be said:
Always create a std::unique_ptr with std::make_unique if possible.
If it needs to be constructed with a raw pointer, never touch the raw pointer after creating the std::unique_ptr with it.
Always be aware, that the std::unique_ptr takes ownership of the supplied raw pointer
Only supply raw pointers to the heap. NEVER use raw pointers which point to local
stack variables (because they will be unavoidably destroyed automatically,
like valin your example).
Create a std::unique_ptr only with raw pointers, which were created by new, if possible.
If the std::unique_ptr needs to be constructed with a raw pointer, which was created by something else than new, add a custom deleter to the std::unique_ptr, which matches the hard pointer creator. An example are image pointers in the (C based) FreeImage library, which always have to be destroyed by FreeImage_Unload()
Some examples to these rules:
// Safe
std::unique_ptr<int> p = std::make_unique<int>();
// Safe, but not advisable. No accessible raw pointer exists, but should use make_unique.
std::unique_ptr<int> p(new int());
// Handle with care. No accessible raw pointer exists, but it has to be sure
// that function_with_runtime_input() allocates the raw pointer with 'new'
std::unique_ptr<int> p( function_with_runtime_input() );
// Safe. No accessible raw pointer exists,
// the raw pointer is created by a library, and has a custom
// deleter to match the library's requirements
struct FreeImageDeleter {
void operator() (FIBITMAP* _moribund) { FreeImage_Unload(_moribund); }
};
std::unique_ptr<FIBITMAP,FreeImageDeleter> p( FreeImage_Load(...) );
// Dangerous. Your class method gets a raw pointer
// as a parameter. It can not control what happens
// with this raw pointer after the call to MyClass::setMySomething()
// - if the caller deletes it, your'e lost.
void MyClass::setMySomething( MySomething* something ) {
// m_mySomethingP is a member std::unique_ptr<Something>
m_mySomethingP = std::move( std::unique_ptr<Something>( something ));
}
// Dangerous. A raw pointer variable exists, which might be erroneously
// deleted multiple times or assigned to a std::unique_ptr multiple times.
// Don't touch iPtr after these lines!
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
// Wrong (Undefined behaviour) and a direct consequence of the dangerous declaration above.
// A raw pointer is assigned to a std::unique_ptr<int> twice, which means
// that it will be attempted to delete it twice.
// This couldn't have happened if iPtr wouldn't have existed in the first
// place, like shown in the 'safe' examples.
int* iPtr = new int();
std::unique_ptr<int> p(iPtr);
std::unique_ptr<int> p2(iPtr);
// Wrong. (Undefined behaviour)
// An unique pointer gets assigned a raw pointer to a stack variable.
// Erroneous double destruction is the consequence
int val;
int* valPtr = &val;
std::unique_ptr<int> p(valPtr);
This example of code is a bit artificial. unique_ptr is not usually initialized this way in real world code. Use std::make_unique or initialize unique_ptr without storing raw pointer in a variable:
unique_ptr <int> uniquePtr2(new int);

Convert a shared_ptr to regular a pointer

We have a function that returns a new allocated object as a output argument (ref to pointer).
MyFunc(MyObject*& obj)
{
obj = new MyObject();
}
Which is called like so:
Object* obj;
MyFunc(obj);
Internally the function does quite a bit and uses shared_ptr for memory management. When it is done, the object we would like to return is referenced by a shared_ptr. I am struggling on how to return our new allocated object as a regular pointer.
We would like to continue to use shared_ptr internally to reduce risks, but it does not seem to make sense to return a shared_ptr as the caller takes complete ownership over the returned value (the called function or object no longer needs or keeps a reference to the returned data) and we want them to have flexibility.
Does anyone have any suggestions for allowing us to use shared_ptr internally but have a regular pointer interface? Thanks
If for some reason you cannot/want not use std::unique_ptr or std::auto_ptr (for example if you need to have multiple owners internally during creation for some reason or your underlying methods require std::shared_ptr to be passed around), you can still make it work with std::shared_ptr by using custom deleter, as described here: https://stackoverflow.com/a/5995770/1274747
In the principle, after you're done before the return, you switch the deleter to not actually delete the instance (make the deleter "null") and then return by shared_ptr get(). Even after all shared_ptr objects are destroyed, the memory will not be deleted (as the nulled deleter will skip the deletion).
There is also a link in the comments not so well visible, which might be of your interest:
http://paste.ubuntu.com/23866812/
(not sure though if it would really work without the shared ownership of the switch in all cases, would need to test)
EDIT
As expected, with the linked simple disarmable deleter from the pastebin you need to be careful, because the deleter is actually copied for storing in std::shared_ptr.
But you can still make it work by using std::ref:
MyFunc(MyObject*& obj)
{
DisarmableDelete<MyObject> deleter;
std::shared_ptr<MyObject> ptr(new MyObject(), std::ref(deleter));
// do what is necessary to setup the object - protected by deleter
// ...
// disarm before return
deleter._armed = false;
obj = ptr.get();
// deleter disarmed - object not freed
}
And just for completeness (and to avoid a potential future broken link), here is the implementation of DisarmableDelete from http://paste.ubuntu.com/23866812/.
template <typename T, typename Deleter = typename std::default_delete<T> >
struct DisarmableDelete : private Deleter {
void operator()(T* ptr) { if(_armed) Deleter::operator()(ptr); }
bool _armed = true;
};
It depends on who "owns" the pointer, once it has been exposed to the 'outside world.' Ownership essentially boils down to: "who is responsible for freeing this memory, later?"
It can be answered with a simple question: when MyFunc is called, is the caller responsible for deleting the pointer when it's done?
If so, then MyFunc needs to 'release' the ownership, otherwise the shared_ptr will automatically delete the pointer, when it goes out of scope. This actually can't be done, using shared_ptr. You need to use a unique_ptr instead, and call unique_ptr::release().
If not - if MyFunc will simply use the resulting pointer and forget about it without delete-ing it - then you can simply return the 'raw' pointer using shared_ptr::get(). You must be careful, because this implies that the shared_ptr still exists elsewhere in your code.
I can see four alternatives, as highlighted below. They are all horrible, and short of switching your ownership to std::unique_ptr<T> and returning via obj = ptr.release(); I can only offer a hack where the argument is assigned to the pointer upon destruction, but you still need to catch the exception and test whether the pointer was assigned.
#include <iostream>
#include <memory>
#include <exception>
struct foo {
void bar() const { std::cout << this << " foo::bar()\n"; }
~foo() { std::cout << this << " deleted\n"; }
};
void f1(foo*& obj) {
obj = new foo;
// do stuff... if an exception is thrown before we return we are
// left with a memory leak
}
void f2(foo*& obj) {
auto holder = std::make_shared<foo>();
// do stuff.. if an exception is thrown the pointer will be
// correclty deleted.
obj = holder.get(); // awesome, I have a raw pointer!
} // oops, the destructor gets called because holder went out of
// scope... my pointer points to a deleted object.
void f3(foo*& obj) {
auto holder = std::make_unique<foo>();
// do stuff.. if an exception is thrown the pointer will be
// correclty deleted.
obj = holder.release(); // awesome, I have a raw pointer!
} // no problem whem holder goes out of scope because it does not own the pointer
void f4(foo*& obj) {
// a super-weird hack that assigns obj upon deletion
std::shared_ptr<foo> holder(new foo, [&obj](foo*& p){ obj = p; });
throw std::exception();
} // no problem whem holder goes out of scope because it does not own
// the pointer... but if an execption is throw we need to delete obj
int main() {
foo* p1;
f1(p1);
p1->bar();
foo* p2;
f2(p2);
// p2->bar(); // error
foo* p3;
f3(p3);
p3->bar();
foo* p4;
try {
f4(p4);
} catch(...) {
std::cout << "caught an exception... test whether p4 was assigned it\n";
}
p4->bar(); // I still need to delete this thing
}
The point of shared_ptr is to express shared ownership.
Anything that does not share in the ownership of an object -- that doesn't have the right to make an object lifetime last longer, and the object lifetime is the union of the shared owners request for object lifetime -- should not use a shared_ptr.
Here, you have a shared_ptr and you are going to return it. At that point, you are violating the assumptions of shared_ptr; anyone who kept a shared_ptr copy expects that its content can last as long as it requests.
Meanwhile, the calling code thinks it owns the MyObject* raw pointer you passed it.
This is an example of misuse of shared_ptr.
Saying "we have memory management issues, use shared_ptr" doesn't fix memory management issues. Proper use of shared_ptr requires care and design, and the design must be that when the end of the lifetime of the object in question is shared by 2 or more pieces of data and/or code.
The internal code, if it does not own the pointer, should use either something like an observer_ptr<T> or a raw T* (the first to make it clear it doesn't own the object).
Ownership should be explicit, and in a unique_ptr. It can then call .release() to pass ownership to a raw pointer if required; in practice, I would change your signature to take a unique_ptr&, or have it return a unique_ptr.
The caller would then call .release() when they want to use some other object lifetime management system, or that object lifetime management system should consume unique_ptrs (thus being extremely clear about taking ownership of things).
Use a non-hack solution.
Such as a std::shared_ptr<std::unique_ptr<T>>. In this case, you have shared ownership of a unique ownership.
The unique_ptr can have its ownership taken from it (via .release()). When it does so, all of the shared_ptrs that still exist will have their unique_ptr also be cleared.
This places the shared unique ownership front and center, instead of hacking a non-deleter into a shared_ptr and having dangling shared_ptrs that think they have ownership over data but do not.
The best approach is to use internally unique_ptr and call its .release() method before returning the raw pointer.
If you are stuck to use shared_ptr internally, an option is to create it specifying a custom, "noop" deleter, that just does nothing when shared_ptr is destroyed (instead of calling delete on the owned pointer). The get the raw pointer from shared_ptr as usual (.get() method).
An example of such a deleter can be found in the Boost library (null_deleter).
But please note that doing this effectively "disable" the usefulness of having a shared_ptr at all...
If your managing the lifespan of the allocated object internally with std::shared_ptr, and are returning a raw pointer for access and don't want this pointer to affect the ref count, you can return the raw pointer by calling shared_ptr.get().
It can be problematic to return smart pointers if your using a tool like Swig to generate wrappers for other languages.

does leaving pointers in functions cause memory leaks?

Suppose I have a function or class that maintains some pointers to other data objects, like so:
class MyObject {
...
AnotherObject* o1, *o2;
SomeObject* s1, *s2;
...
}
int main() {
...
MyObject mo1 = new MyObject();
... // do stuff with mo1
delete mo1;
}
Suppose they are assigned valid pointer values from elsewhere during/after initialization.
When I destroy the MyObject object after assigning those pointers inside, can a memory leak result if I do not null the pointers during destruction like so?:
MyObject::~MyObject() {
o1 = nullptr;
o2 = nullptr;
...
}
Thanks.
No it won't cause a memory leak. Note however that this:
MyObject mo1 = new MyObject();
// do stuff with mo1
delete mo1;
will result in a memory leak if do stuff with mo1 throws an exception (which could be the case if it comprises references to nullptr). Therefore it's advisable not to use naked pointers like you do but smart pointers instead - this way RAII guarantees that your pointer will be deleted.
It sounds like you come from a Java background, where setting pointers to null is necessary to allow the garbage collector to reclaim other objects. If so, the answer is simple: no, that's not how it works in C++. Setting a pointer to null has no bearing whatsoever on memory usage, and there is no garbage collector anyway that could reclaim any memory.
Instead you are supposed to consider ownership. Most objects have one specific owner; once that owner is deleted, so are its owned objects. This is most conveniently modelled using unique_ptr instead of raw pointers. For objects that have more complex ownership, there is shared_ptr and weak_ptr.
Once again, there is no garbage collector, so any time you use new to create an object, somehow, somewhere there must be a corresponding delete. The easiest way to ensure such deletes are not forgotten is to use unique_ptr.
Also be wary of using new too often. Your mo1 object can be allocated on the stack without any problem: it's lifetime is limited to one function (main), so why not use simply allocate it as MyObject mo1; - that's enough, no need to new or delete anything.
No it would not. Memory leak happens because of a non-deleted memory which was allocated using new. Nulling a pointer is just a way to check it later if it was deleted or not and it has nothing to do with memory leak.
On the other hand, dealing with memory manually is not a the best way to achieve what you want. Smart pointers are exist (std::shared_ptr, std::unique_ptr...). You should have a look on them.

Assigning existing values to smart-ptrs?

I am just learning about smart pointers, and I am having trouble assigning a pre-existing location of a variable to the standard library's shared pointer.
For example, lets say you have an int x, which you do not know the value of. With normal pointers, I just did
int* ptr;
ptr = &x;
I tried both that with shared pointers, and
std::tr1::shared_ptr<int> ptr;
ptr = std::make_shared<int> (&x)
So i'm fairly lost as to how to do it.
You wouldn't (usually) make a smart pointer point to an existing variable. A smart pointer manages the lifetime of a dynamically allocated object, deleting it after use; pointing it to something that wasn't dynamically allocated will cause an error if it tries to delete it.
You would usually use new or make_shared to create an object, and create or assign a smart pointer with the result of that:
std::shared_ptr<int> ptr(new int(42)); // Create a new pointer to manage an object
ptr.reset(new int(66)); // Reset to manage a different object
ptr = std::make_shared<int>(53); // Use `make_shared` rather than `new`
make_shared is usually preferable to new, since it makes better use of memory and gives stronger exception-safety.
Shared pointers are used to manage dynamically allocated memory and more precisely, they manage the ownership for this memory.
Basically, a smart pointer is a materialization of the Ressource Acquisition Is Initialization, or RAII. I strongly suggest you take a look at this principle, as it is extremely useful for managing resource ownership (basically, each time you need to acquire a resource, and release it, be it memory, a database connection, a file handler, a mutex, etc.).
What it does is basically guarantee that while someone points at the dynamically allocated memory it manages, then this memory will be available, and as soon as the last (smart) pointer to this memory goes out of scope, then delete is called.
Then, it makes no sense to use smart pointers with variable that have automatic storage duration (i.e. that are removed when they go out of scope or when the object they're member of goes itself out of scope or is deleted (if it was new'd).
You should not create a smart pointer pointing to an object that is not dynamically allocated. Otherwise the smart pointer may try to delete the allocated memory which in turn will cause an error.
as soon as the reference counter of the shared_ptr reaches zero, the object will be deleted by the last shared_ptr. with smart pointers you can specify the function which shall delete that object.
the Deleter is a simple function (defaults to the usual operator delete) that has to be bound to the smart pointer, either statically via template parameter (see unique_ptr) or dynamically via constructor parameter (see shared_ptr).
// dynamically via shared_ptr:
// shared_ptrs share the pointer to the Deleter
// because they already share a common data structure for reference counting.
auto ignore = [](int* o){
std::cout<<"i will refuse to delete this object: " << o << "\n";
std::cout<<"not my responsibility." <<std::endl;
};
std::shared_ptr<int> sptr(&x,ignore);
//statically via unique_ptr:
// actually, the unique_ptr is as data structure not more than a regular pointer.
// but a pointer with special copy-constructor and destructor,
// which will most likely be inlined.
// there is no space to store a reference to a Deleter dynamically.
struct IgnorantDeleter{
void operator()(int* o){
std::cout<<"who ate my cake? " << o << "\n";
std::cout<<"but i baked it." <<std::endl;
}
};
std::unique_ptr<int,IgnorantDeleter> uptr(&x);