1

I know this kind of questions aren't really welcome here but I must ask: why don't unique_ptr/shared_ptr/etc have an operator= overload for type T?

It would seem more natural to write

std::unique_ptr<int> p = new int(5);

instead of

std::unique_ptr<int> p(new int(5));

or any other more verbose method.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
user1233963
  • 1,450
  • 15
  • 41
  • Actually I'm wrong, your first form didn't compile either ;-) Sorry! (It is calling the constructor, but it looks like it can't create a temporary to pass to the copy ctor.) – Cameron Feb 17 '13 at 01:02
  • I know it doesn't compile, that's the point – user1233963 Feb 17 '13 at 01:03
  • Looks like a duplicate of [this question](http://stackoverflow.com/q/757465/21475) -- [this answer](http://stackoverflow.com/a/757574/21475) explains the rationale is to avoid pointers being accidentally assigned (and memory taken ownership of) without that being the intention. You work around this by creating explicit temporary objects and assigning those. – Cameron Feb 17 '13 at 01:08
  • 3
    Assignment operators have exactly *nothing* to do with your code. – Kerrek SB Feb 17 '13 at 01:14

2 Answers2

6

If you were allowed to write this:

std::unique_ptr<int> p = new int(5);

Then you would also be allowed to write these:

void Func1(std::unique_ptr<int> p);

Func1(new int(5));

std::unique_ptr<int> Func2() {return new int(5);}

Or the far more dangerous:

void Func1(std::unique_ptr<int> p);

int *pInt = new int(5);
Func1(pInt); //You no longer own the pointer anymore.
delete pInt; //You're now deleting a pointer you don't own.

That's not acceptable for obvious reasons. They don't want implicit conversion from naked pointers to unique pointers; if you want to create a unique_ptr, you must be explicit about it: Func1(std::unique_ptr<int>(pInt)); Now, everyone can see that you're transferring ownership from yourself to the function.

Also, it's not an operator= that would make this works. It's the explicit on the single-argument constructor of unique_ptr that stops the copy-initialization syntax from working.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • If we go by this we shouldn't be allow to do this either: int* p = new int(5); std::unique_ptr temp(p); delete p; – user1233963 Feb 17 '13 at 01:11
  • 2
    @user1233963: Then there would be no way to put a pointer into a `unique_ptr`. The goal is to ensure that you don't do it by accident, without seeing ***`unique_ptr`*** sitting there at the site where the transfer of ownership takes place. Due to the rules of C++, this also means that you can't use copy-initialization (aka: `typename var = stuff;`) you must use direct initializaton (aka: `typename var(stuff);`). – Nicol Bolas Feb 17 '13 at 03:31
2

What you're referring to is the fact that the constructor of unique_ptr<T> that takes a raw T pointer is explicit. This is deliberate. A unique pointer takes ownership, and that should not happen implicitly. The user should always know explicitly when ownership is created, transferred and ended.

In a more draconian world one could imagine a unique_ptr that doesn't take any raw pointers at all, and instead only allows direct creation of the owned object:

auto p = std::unique_ptr<T>::make(arg1, arg2, arg3);
                             // Calls "new T(arg1, arg2, arg3)".
                             // Not real code.
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • then why can we do this: int* p = new int(5); std::unique_ptr temp(p); ? – user1233963 Feb 17 '13 at 01:22
  • @user1233963: because that's an *explicit* conversion. You're explicitly saying, "now `temp` owns `*p`". – Kerrek SB Feb 17 '13 at 01:23
  • i can still call delete on p and make it crash and burn. Writing std::unique_ptr p = new int(5); is way more clear and doesn't allow accidental deletion in my opinion – user1233963 Feb 17 '13 at 01:26
  • 3
    @user1233963: You can also write `int x = 0; delete &x;` and burn. Nobody was claiming that C++ is safe. It's just *harder* to write unsafe code. As I said, in a perfect world there wouldn't be any raw pointers exposed in user code and no `new`. – Kerrek SB Feb 17 '13 at 01:28