11
votes

Consider the following code snippet:

class Owner {
public:
 Owner(std::unique_ptr<int> ptr) : owned_pointer<int>(std:move(ptr)) {}
private:
 std::unique_ptr<int> owned_pointer;
};


std::unique_ptr<int> ptr(new int);
int* ptr1 = ptr.get();
Owner new_owner(std::move(ptr));

Is it safe to assume that ptr1 is valid as long as new_owner stays in scope? It seems to work, but I can't find a specification that states that explicitly - is it undefined behavior/implementation specific and just happen to work for me, or the code posted above is valid (ptr1 is guaranteed to point to moved pointer as long as it stays alive)?

2
unique_ptr<int> stores a value that is of type int*. On destruction, it calls delete on it (through a traits class). ptr.get() returns a copy of the int*. new_owner transfers ownership of that int*, so the old unique_ptr won't delete it and the new one will. Nothing magic should be going on. Unless you are looking for a standardese tea leaf reading and are interested in possible holes/errors in the standard?Yakk - Adam Nevraumont
@Yakk, yes I am looking more for the standard specification or relevant stl documentation - I understand it is implemented as you described and hence it works. But I would like to guard against the possibility of next gcc release implementing unique_ptr differently and breaking the posted code - does the standard guarantee this to always work?Ilya Kobelevskiy
Honestly, it is pretty clear to me that this is one of the cases where if the standard disagrees with the implementation, the standard is wrong (wrt the lifetime of the int*). This isn't like iterator abstractions around lifetime issues with vector, where practical and standard defined behavior can and probably should differ. So any standard tea leaf reading that disagrees would just mean there is a bug in the standard. I suppose such a bug in the standard, if not noticed, might lead gcc to implement the bug in a future iteration?Yakk - Adam Nevraumont

2 Answers

8
votes

Yes, it is valid.

You can have multiple (plain) pointers pointing to the same object. The question is how long those pointers are valid or when the object pointed to is deleted.

A unique_ptr stores one more plain pointer and takes ownership, meaning it is responsible for when the object is destroyed. Moving it to another unique_ptr just transfers ownership, the object itself is still the same and all plain pointers pointing to it remain valid.

Only when the ownership is not transferred (or released) and the owning unique_ptr is destroyed, it also destroys the object. This would be the moment where all plain pointers pointing to the object become dangling pointers and dereferencing them would be illegal.

7
votes

Yes, the C++11 specification guarantees that transferring ownership of an object from one unique_ptr to another unique_ptr does not change the location of the object itself, and that get() on the second unique_ptr returns the same as it would have on the first unique_ptr before the transfer.

Looking at N3337, section 20.7.1:

  1. Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following postconditions hold:

    • u2.p is equal to the pre-transfer u.p,
    • u.p is equal to nullptr, and
    • if the pre-transfer u.d maintained state, such state has been transferred to u2.d.

where u is a unique_ptr object that stores a pointer u.p.

The first bullet answers the question directly, since get() is specified as returning the u.p.