简体   繁体   中英

Why can a unique_ptr be created from another unique_ptr get() without causing an error?

I'm new to C++ and smart pointers, especially the behavior of unique_ptr. Below is a piece of code that I'm experimenting:

unique_ptr<int>  u1 = make_unique<int>(2);
unique_ptr<int>  u2 = make_unique<int>();
u2.reset(u1.get());

unique_ptr, by definition, is a kind of smart pointer which doesn't share the ownership of the object that it is pointing to with other smart pointers. However, why doesn't the above code return an error? In fact, if I try to print the value of u1 and u2 out, they turn out to indeed point to the same memory address:

cout<<u1.get()<<endl;
cout<<u2.get()<<endl;

Show these on the Console:

0x55800839ceb0
0x55800839ceb0
free(): double free detected in tcache 2 // finally the error appears at the end of the program's execution

But if I say:

cout<<(*u1)<<endl;
(*u1)=5;
cout<<(*u2)<<endl;

The change doesn't affect (*u2), as if they are in different memory addresses.

Any help would be appreciated! Thank you for your time!

As soon as you call get() , you have a raw pointer. It's just a pointer, and it carries no significant ownership semantics that the standard library or language can preserve or provide.

You then use that pointer to make a second unique pointer take ownership of the object being pointed at. It "thinks" that it has sole ownership of the object. This is perfectly fine, as long as that unique pointer really is the only thing owning that object.

Unfortunately, the first unique pointer still owns the very same object, and so there will be a double-free when both unique pointers try to destruct the object. This is undefined behavior, and a clear error message at compile time is not guaranteed. You may have subtle corruption, a silent crash, or the program may silently succeed by chance alone.

However, a sanitizer can show a clear error at runtime more reliably when it's enabled, since it's actively on the lookout for certain types of undefined behavior. Here's a demo showing ASan (the Address Sanitizer) detecting this double-free, as it is designed to do.

The change doesn't affect (*u2), as if they are in different memory addresses.

It does; see the above demo which prints 2 2 2 5 ( u1 , u2 , u1 before updating, u2 after u1 is updated).

However, why doesn't the above code return an error?

Because compilers are not magical .

unique_ptr::reset is a legitimate function, allowing a unique_ptr to adopt a new, potentially unowned pointer. unique_ptr::get is a legitimate function, allowing a user to access the pointer being managed.

The fact that calling both in succession is almost certainly a bug is not something a compiler can diagnose. And even if they did, all you'd need to cause the same problem is to hide the get from the reset . A function between them that passes through its parameter would be enough.

Even having something like unowned_ptr<T> , a "smart" pointer that just wraps the T* , returned by get wouldn't solve it, as you have to be able to access the T* if you want to do anything with that unowned_ptr<T> .

At some point, programmers have to take responsibility for the correctness of their programs. Tools like unique_ptr can help, but eventually, a user's judgment must be trusted.

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