What happens to a pointer after it has become a unique_ptr? - c++

I have a function that creates a unique pointer to a dynamically allocated object "c".
template<typename T, typename... TArgs> void addComponent(TArgs&&... MArgs) {
if(!components.count(typeid(T))) {
T* c = new T(std::forward<TArgs>(MArgs)...);
c->entity = this;
std::unique_ptr<Component> uPtr{ c };
components[typeid(T)] = (std::move(uPtr));
c->init();
}
}
My understanding is that the unique_ptr takes control of the value of c because you can't have another pointer pointing too a unique_ptr, however c->init still works after c has been turned into a unique_ptr.
Why does this work? Does c somehow still point to the same new T() or is an entirely new object created?

The unique_ptr object stores a copy of the value of c. When the unique_ptr object is destroyed, its destructor will call delete on the stored pointer value.
The original variable c is not modified by the unique_ptr, and continues to point to the same object. It is perfectly fine to dereference it. The important thing is that since this pointer value will be deleted automatically by the unique_ptr, (1) you must not continue using its value after the unique_ptr's lifetime expires, and (2) you must not try to delete it manually.

Wrapping a raw pointer inside of a smart pointer does not change anything about the raw pointer. It still points at the same memory it was originally pointing at. The smart pointer is merely copying the pointer and then managing the pointed-at memory for you, delete'ing the memory when the smart pointer is destroyed or is otherwise assigned a different pointer.
FYI, it would be more safer and more efficient to use std::make_unique() instead of new, eg:
template<typename T, typename... TArgs>
void addComponent(TArgs&&... MArgs) {
if (!components.count(typeid(T))) {
auto c = std::make_unique<T>(std::forward<TArgs>(MArgs)...);
c->entity = this;
c->init();
components[typeid(T)] = std::move(c);
}
}

No new objects are created and nothing takes control over anything. You wrapped the raw pointer with the smart pointer, and should not use the raw pointer anymore.
The smart pointers only work if you don't work around them by using the raw pointer. But the value of the variable c doesn't change because of the assignment operator in std::unique_ptr constructor. It remains the same, and you as the programmer should be disciplined about not using it directly any more.
Good practice would be to have it as a temporary variable that disappears after it's wrapped into a smart pointer; or instead of new just use std::make_unique.

Related

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.

How to use unique_ptr with data allocated within a c library?

I'm in c++ and i'm writing a wrapper around a c library. The c library function i'm working with takes a type 'LDAPMessage **' as a parameter, where it will allocate the memory for you within the function. Normal usage looks like this:
LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me
Now I want to use unique_ptr in this case, with a custom deleter. Assume my deleter 'LDAPMessageDeleter' exists and works in the following.
unique_ptr<LDAPMessage*, LDAPMessageDeleter> msg_ptr(new LDAPMessage*);
c_lib_function(msg_ptr.get());
Though this compiles for me, i'm getting a seg fault. Could this code be at fault here? Is this correct usage of unique_ptr?
It might be easier to do e.g.
LDAPMessage* msg;
c_lib_function(&msg);
// Now we have out pointer (hopefully)
std::unique_ptr<LDAPMessage, LDAPMessageDeleter> msg_ptr(msg);
Of course, the LDAPMessageDeleter have to call the proper function to free the memory (e.g. free is the memory was allocated with malloc).
The problem with the code you show in the question, is that you try to create a pointer to a pointer, but don't make that first-level pointer actually point anywhere.
What you are effectively doing in your code is this:
LDAPMessage** msg;
c_lib_function(msg);
What's happening in the C library, is that the pointer is passed "by reference". Since C doesn't actually have proper references, it's kind of emulated by passing pointers. And passing a "reference" to a pointer is done by using the address-operator to pass the address of the pointer (which then becomes a pointer to the pointer).
Someone in the SO chat developed code valuely like this that I can no longer find:
//ptrptr magic
#include <memory>
template<class T, class deleter>
class ptrptr_type {
public:
ptrptr_type(std::unique_ptr<T, deleter>& ptr)
: uptr(&ptr), tptr(ptr.get()) {}
~ptrptr_type() {if (uptr->get()!=tptr) uptr->reset(tptr);}
operator T**() {return &tptr;}
private:
std::unique_ptr<T, deleter>* uptr;
T* tptr;
};
template<class T, class D>
ptrptr_type<T,D> ptrptr(std::unique_ptr<T, D>& ptr) { return {ptr};}
And the usage of this ptrptr is quite simple:
std::unique_ptr<LDAPMessage, LDAPMessageDeleter> my_ptr; //can be null or initialized, whichever
c_lib_function(ptrptr(my_ptr)); //use ptrptr(my_ptr) whenever you need a T**
That's it. Real simple. http://coliru.stacked-crooked.com/a/644ed001ffd547ae
What happens is ptrptr(my_ptr) creates a temporary ptrptr_type on the stack, which takes the pointer from the unique_ptr. The ptrptr then exposes a pointer to it's internal pointer, which the C function can freely modify. Afterwards, the temporary ptrptr_type is destroyed, and its destructor puts the new value for the pointer back into the original unique_ptr.
This isn't correct usage of the pointer-to-pointer. The function takes a pointer to uninitialized pointer and fills it. In your first example, this is a local variable. If you want it to be managed by unique_ptr, it should still be a local, just contained within the unique_ptr object.
LDAPMessage * msg;
c_lib_function(&msg); // allocates the memory for me
std::unique_ptr< LDAPMessage, LDAPMessageDeleter > // This type contains a ptr
msg_ptr( msg ); // transfer ownership to C++
LDAPMessageDeleter should receive a LDAPMessage *, and pass it to the library to be released if necessary, otherwise pass to free().

Should a pointer be the same before and after adding to a unique_ptr?

I have a std::vector of unique_ptrs and I'm happy to have them manage the life cycle of those objects.
However I require storing other pointers to those objects for convenience. I know that once unique_ptr removes something, those other pointers will dangle. But I'm more concerned about the validity of those pointers before and after unique_ptr gets them.
I do not always create via new within the unique_ptr itself, for example I might pass new Something as a function parameter in which case the unique_ptr is using move on that pointer into itself inside the function.
But I might also new Something before I pass it into a function that then assigned it a unique_ptr.
Once an object is assigned to a unique_ptr I can get a pointer to it via get(). But can I always assume that this get() pointer points to the same place as the pointer initially obtained via new if the original pointer was created before the assignment to a unique_ptr ?
My assumption is Yes, and that even if the vector resizes and reallocates, the unique_ptr as well as any other pointers to the objects in memory remain the same.
Yes, a std::unique_ptr<T> holds a pointer to T, and it will not alter the value between initialization and later retrieval with get()
A common use of a unique_ptr is to assign one "parent" object ownership of a dynamically-allocated "subobject", in a similiar same way as:
struct A
{
B b;
}
int main()
{
A a = ...;
B* p = &a.b;
}
In the above b is a true subobject of A.
Compare this to:
struct A
{
unique_ptr<B> b = new B(...);
}
int main()
{
A a = ...;
B* p = a.b.get();
}
In the above A and (*b) have a similar relationship to the first example, except here the B object is allocated on the heap. In both cases the destructor of A will destroy the "subobject". This "on heap" subobject structure may be preferable in some cases, for example because B is a polymorphic base type, or to make B an optional/nullable subobject of A.
The advantage of using unique_ptr over a raw pointer to manage this ownership relationship is that it will automatically destroy it in As destructor, and it will automatically move construct and move assign it as part of A.
As usual, in both cases, you must be careful that the lifetime of any raw pointers to the subobject are enclosed by the lifetime of the owning object.
Yes, you are correct, because unique_ptr does not copy the object; therefore, it has to point to the same address. However, once you give a pointer to a unique_ptr to own, you should not use that raw pointer any more, because the unique_ptr could be destroyed and deallocate the memory, and turn your raw pointer into a dangling pointer. Perhaps shared_ptr would be better for your situation.

When using shared_ptr should I just use the shared_ptr declaration once or declare shared_ptr everywhere I pass it?

When using shared_ptr, should I just use the shared_ptr declaration once or declare shared_ptr everywhere I pass it?
So in the function where I new up the instance I wrap it in a shared_ptr but when I return it from the function I could also return a shared_ptr or, using the get() on the shared_ptr, just return a normal pointer.
So my question is, should I just use shared_ptr<myType> when I new the instance and then pass normal pointers around or should I be passing shared_ptr<myType> everywhere?
Creating a shared_ptr doesn't imbue magical powers on its pointee object. The magic is all in the shared_ptr — and its copies — itself. If you stop using it, you lose your reference counting; worse, because you used it at some point, the object will be automatically deleted when you don't expect it.
The whole point of having shared_ptr is that you know your object won't get destroyed when you're still using it somewhere.
In the following:
T* foo() {
shared_ptr<T> sp(new T());
return sp.get();
// ^ the only shared_ptr<T> referencing the obj is dead;
// obj is deleted;
// returned pointer invalid before you can even do anything with it
}
your pointer is immediately invalid.
There may well be circumstances in which you extract a raw pointer, but these should be rare. If you are in a function where you know you don't need the reference counting, then just pass the shared_ptr in by reference.