3

This SO post seems to suggest that language indeed supports accepting temporaries only for arguments.

Why is then unique_ptr designed to accepted aliased pointers, like this:

auto ptr = new Widget{};
auto uptr = std::unique_ptr<Widget>(ptr);

Why not just restrict to:

auto uptr = std::unique_ptr<Widget>(new Widget{});
Community
  • 1
  • 1
winterlight
  • 460
  • 4
  • 10
  • 1
    Why not restrict it to just `std::make_unique()` instead? – user975989 Jul 18 '16 at 17:43
  • 4
    The first scenario is actually pretty valid, though it could easily become exception-unsafe if more code is added between the two lines. The first pointer is said to be an observer pointer, while the `uptr` is called the "owning pointer". There's nothing wrong with having multiple observer pointers to the same resource. Also, `std::unique_ptr` should accept taking ownership from existing "raw owning pointers" so it can be used in existing codebases without breaking the existing APIs. – KABoissonneault Jul 18 '16 at 17:59
  • @KABoissonneault, in that case you could use `std::unique_ptr up(std::move(ptr));` which flags that you are doing something potentially dangerous. See my answer. – alfC Jul 18 '16 at 18:18
  • 1
    @alfC It might just be me, but I don't think using rvalue references with fundamental types is ever the right solution to any problem. – KABoissonneault Jul 18 '16 at 18:23
  • @KABoissonneault, then the question is `unique_ptr` a fundamental type? It definitively is not like an `int` (pure value semantics). It is a matter of taste ultimately because it is a detail. But if we *all* (?) agree that "Not assigning an object(raw pointer) to a `unique/shared_ptr` as soon as it is created !" is a mistake then why not enforce it in the library, we now can enforce it and we also have a workaround if one wants to play dangerously. This is the typical thing that makes embarrassing to teach C++ to beginners. – alfC Jul 18 '16 at 18:29
  • 1
    @alfC: "*then the question is unique_ptr a fundamental type?*" He's talking about taking a `T*&&`. Pointers are fundamental types. As for the rest, we *don't* all agree. Or at least, not to the point where we should enforce it at the level of the library. – Nicol Bolas Jul 18 '16 at 18:58
  • @NicolBolas, we in the technical evaluation of the problem. My problem is went we make smart-sounding "guideline" or call people ["dumb"](http://www.acodersjourney.com/2016/05/top-10-dumb-mistakes-avoid-c-11-smart-pointers/) instead of recognizing that the library may have design oversights. We can at least say that the design has a strange case a recommend people to avoid something from that humble position. In this particular case a the alternative design has zero cost and we wouldn't need any extra guideline rule. – alfC Jul 18 '16 at 19:26

2 Answers2

1

Because this doesn't help.

It's required that the pointer is created by a suitable allocation function for the given deleter, which is different to it being temporary.

You can't distinguish pointers created by a new expression, function call and by & operator by a value category - they are all rvalues.

milleniumbug
  • 15,379
  • 3
  • 47
  • 71
  • "It's required that the pointer is created by using `new` expression" -- No, it's not. The default deleter requires this, but other deleters can and are used too. –  Jul 18 '16 at 17:52
  • Fair point. However, the `unique_ptr` constructor is not limited to the scenario mentioned by the OP, so any rationale that applies only to that scenario is somewhat flawed, in my opinion. –  Jul 18 '16 at 17:55
  • So, there is no way in C++ language to avoid this kind of aliased pointer? – winterlight Jul 18 '16 at 17:55
  • 2
    @winterlight: No. You can always create a function that takes a pointer and returns an rvalue reference to that same pointer. Indeed, we have one; it's called `std::move`. You can always turn any non-rvalue expression into an rvalue expression. – Nicol Bolas Jul 18 '16 at 17:58
  • @winterlight You can design your own `unique_ptr` class that can only be created with the `make_unique` factory function (tip: use private constructors and the `friend` keyword to achieve this). – KABoissonneault Jul 18 '16 at 18:00
  • @KABoissonneault, agreed. – winterlight Jul 18 '16 at 18:06
  • @NicolBolas, "You can always turn any non-rvalue expression into an rvalue expression" - I see your point but somehow feel it is made too easy to pass an lvalue (`ptr`) to the unique_ptr constructor as in the question. – winterlight Jul 18 '16 at 18:15
  • @winterlight: But passing an lvalue to the constructor is not an error. – Nicol Bolas Jul 18 '16 at 18:18
0

There is no good reason as far as I know, I think it this an underexploitation of the C++ language from the library.

I asked the same question Why is raw pointer to shared_ptr construction allowed in all cases?

I still don't find a good reason for not making the constructor of std::unique_ptr accepting only r-value references, either from new or from a factory. Here I put it as answer and not as a comment to put it in at the same level of the other answer with which I don't agree.

If you really need to accept an existing pointer, you can always cast, that is use std::move. So it is not an excuse, because that is not the norm.

Community
  • 1
  • 1
alfC
  • 14,261
  • 4
  • 67
  • 118