2

I have been working on std::unique_ptr s but confused at some point about its semantics. From the documentation,

No two unique_ptr instances can manage the same object

But, even tough it is most probably a silly example, consider such a code.

std::unique_ptr<int> a(new int(10));
std::unique_ptr<int> b = std::unique_ptr<int>(a.get());
std::cout << *b << std::endl;
*a = 5;
std::cout << *b;

a and b is managing the same object here, and the output is 10 5. And of course I am getting an assertion failure error at the end on debug mode due to two unique ptrs trying to destruct same object at the end of scope.

I know it is silly and such usage is not advised, but I came across to this when it was not very obvious ( a class member calling another etc. ) and the assertion failure was the thing I started with.

My question is what the above sentence exactly means: it is posed by the standard and a decent compiler shouldnt allow you to do it (i am on vs2013 btw) or you must do it that way ( never cause two unique_ptrs point to same object) ( unlikely since the purpose of unique_ptrs is to make us less worried i suppose.) Or I should never use anything about raw pointers ( a.get() ) when unique_ptr s are involved.

bahti
  • 626
  • 1
  • 7
  • 21

1 Answers1

2

Your last sentence is correct. As soon as you use raw pointers with a.get() as in the line below, you have thrown away all the promises that std::unique_ptr make to you.

std::unique_ptr<int> b = std::unique_ptr<int>(a.get());

The correct semantic to preserve the uniqueness while converting to a raw pointer would be to use a.release().

std::unique_ptr<int> b = std::unique_ptr<int>(a.release());

Of course, you would normally just use assignment or initializatoin with std::move if you were moving ownership between two std::unique_pointer instances, as given by the documentation. Either of the two lines below should be valid.

std::unique_ptr<int> b(std::move(a));
std::unique_ptr<int> b = std::move(a);

To make the std::move semantics more clear, consider the following test program.

#include <stdio.h>
#include <memory>
#include <stdlib.h>


int main(){
    std::unique_ptr<int> a(new int(10));
    printf("%p\n", a.get());
    std::unique_ptr<int> b(std::move(a));
    printf("%p\n", a.get());
    printf("%p\n", b.get());
}

On my system, the output is the following. Observe that the first line and the last line match.

0x1827010
(nil)
0x1827010
merlin2011
  • 63,368
  • 37
  • 161
  • 279
  • You need to use `std::unique_ptr b = std::move(a);`. You must use move assignment for `std::unique_ptr`. – ECrownofFire May 18 '14 at 01:09
  • @ECrownofFire, Fixing, thanks... I should have checked. – merlin2011 May 18 '14 at 01:09
  • I am having hard times understanding move semantcis. As i understand it, this line will make b point to whatever pointed to by a, and make a point to null, right? – bahti May 18 '14 at 01:14
  • @bahti, Roughly speaking, yes. [This question](http://stackoverflow.com/questions/3413470/what-is-stdmove) gives more details. – merlin2011 May 18 '14 at 01:16
  • The link you provided is really helpful, thanks. But now I think of copy constructors of classes with unique ptr members. If the unique_ptr is Base class pointer pointing to a Derived class , we cannot use ( new Base(*foo.uniqueptrmember) nor this.uniquptrmember = std::move(foo.uniqueptrmember) since foo is constant. What could be the possible solution? – bahti May 18 '14 at 01:45
  • @bahti, I do not entirely understand the question, since you seem to be conflating inheritance with the copy constructors. If you are trying to copy a class with a unique pointer, I would assume the normal case is to make a deep copy, and duplicate the object that the pointer is pointing at. [This discussion](http://stackoverflow.com/questions/15648844/using-smart-pointers-for-class-members) may be informative for the more general case. – merlin2011 May 18 '14 at 01:51
  • @merlin2011 Well, let me try to explain it. Let's say, I have a class Foo which has a data member std::unique_ptr bar . In the copy constructor, i could have done: bar(new Base(*other.bar)) if it was not a Base class ptr. – bahti May 18 '14 at 01:56
  • @bahti, If this is a somewhat involved question, it probably makes more sense for both semantic and formatting reasons to [ask a new question](http://stackoverflow.com/questions/ask), with code samples to make everything super-clear. :) – merlin2011 May 18 '14 at 01:58
  • @merlin2011 may be i should do that :) – bahti May 18 '14 at 02:02
  • here I asked a question about this discussion http://stackoverflow.com/questions/23717967/copy-constructor-for-a-class-that-has-unique-ptr-of-a-base-class – bahti May 18 '14 at 02:26