简体   繁体   中英

Why does the std::unique_ptr constructor accept an external pointer?

I'm relatively new to cpp, and am learning about smart points. I'm wondering the following:

Why is constructing an std::unique_ptr with an lvalue allowed?

Wouldn't it be safer to only allow the construction of an std::unique_ptr with rvalues to avoid evil things?

std::unique_ptr<int> createInt() {
    int* a = new int(99);
    std::unique_ptr<int> foo(a);
    delete a;
    return foo;
}

I realize you'd have to be crazy to write something like that but I'd be nice to have the compiler yell at you for it. So I'm left wondering, why is lvalue initialization of unique_ptr a thing?

EDIT : User @aler egal put my thoughts more elagantly:

"In principle, you could have a constructor unique_ptr<int>(int*&& ptr) which assumes ownership of ptr and then sets it to null . That would prevent a use-after-free in this specific example (because you'd be forced to std::move(a) and because calling delete on a null pointer has no effect) but it would be a very strange anti-pattern."

This is a classic example of what a dangling pointer is! In contrast to what smart pointers may seem, they are simply wrappers over normal (raw) pointers, which can manage memory on their own and give you some added functionalities.

Consider the following example:

int* someFunc() {
    int* ptr;
    int* ptr2 = ptr;
    delete ptr;
    return ptr2;
}

This is what you are essentially doing.
They have been made such that they can be used instead of raw owning pointers at all times ; meaning, they can be dangled too! So, if they are not allowed lvalue initialisation, that's one use case where you can't use a smart pointer, although I agree, this is one case where you are not to use either!

The above code with smart pointers will be exactly what you tried.

Now, C++ leaves logic to you... entirely. If you want to shoot yourself in the foot, go ahead, C++ won't bark. C++ does not check for memory usage and buffer overflows and access of deleted memory. Simply speaking, it's the job of a C++ programmer and if he/she wants to shoot himself/herself in the foot, he/she's free to do so!


Also, it is usually recommended to use std::make_ptr() over the ctor, as the former is exceptions enabled

There is a well-known design principle that suggests designs be kept not just simple, but stupid-simple. Adding complexity to the simplest possible implementation requires a justification. In this case, the suggested justification is the avoidance of evil things like the following:

std::unique_ptr<int> createInt() {
    int* a = new int(99);
    int* b = a;
    std::unique_ptr<int> foo(b);
    delete a;
    return foo;
}

Oops. Looks like I changed something (introduced a new variable, b ), but the same evil result is there. Only... in this form, forcing move-construction would not help. Even if b was set to null after construction, the value of a would be untouched. (This form would require something analogous to move-constructing a unique_ptr from a shared_ptr , but such a constructor does not exist – for good reason.)

So you end up introducing complications to the implementation of the constructor (it would need to null-out the provided pointer) and to uses of the constructor ( foo(a) would need to become foo(std::move(a)) ), yet the problem is not really solved. If the language's highest goal was safety, the complication might still be justified. However, C++ ranks performance (you only pay for what you use) over safety.


A lot of the safety features of C++ are there to ensure something good gets done, such as releasing memory. There is very little done to stop something bad from being done, such as releasing the same memory twice. Some bad things trigger warnings from some compilers, but in the end, the programmer gets what the programmerwantsasks for.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM