Why is there no alias constructor like std :: shared_ptr in std :: unique_ptr?

I just discovered the smoothing constructor std::shared_ptr "and wonder:" Why doesn't std :: unique_ptr have one?

That is, if you want to allocate Foo so that you can pass its Bar member to a function that should completely control Foo lifetime, would it be nice to be able to do this?

 #include <memory> struct B {} struct A { B b; } void f(std::unique_ptr<B> b); std::unique_ptr<A> a = std::make_unique<A>(); std::unique_ptr<B> b { std::move(a), &(a->b) }; // a now invalid. f(std::move(b)); // f now responsible for deleting the A. 

This works with std :: shared_ptr ( http://ideone.com/pDK1bc )

 #include <iostream> #include <memory> #include <string> struct B { std::string s; }; struct A { B b; A(std::string s) : b{s} {}; ~A() { std::cout << "A deleted." << std::endl; } }; void f(std::shared_ptr<B> b) { std::cout << "in f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl; } int main() { std::shared_ptr<A> a = std::make_shared<A>("hello"); std::shared_ptr<B> b { a, &(a->b) }; a.reset(); // a now invalid. std::cout << "before f, b->s = " << b->s << " (use_count=" << b.use_count() << ")" << std::endl; f(std::move(b)); // f now responsible for deleting the A. std::cout << "after f" << std::endl; return 0; } 

displays the expected

 before f, b->s = hello (use_count=1) in f, b->s = hello (use_count=1) A deleted. after f 

Is there a logical reason why such a thing was not included? And / or is it a bad idea to emulate it with unique_ptr<B> with a custom delete that removes A ?

+5
source share
2 answers

I believe the β€œproblem” is that, unlike std::shared_ptr , std::unique_ptr deleter is not erased. The default outcome is std::unique_ptr<T> (which is of zero size, encoded in the type itself as a barely visible default parameter) simply [](T * p){ delete p; } [](T * p){ delete p; } . But it is clear that a std::unique_ptr<B> created using std::make_unique<B> , and one that was created by specifying element B object A , cannot have the same debiter. For the last case, a deleter would have to do some pointer arithmetic to get the correct A * pointer. These two deletes can only be of the same type if both store an offset or an internal pointer to the source object. And it will no longer have zero size. std::unique_ptr was designed to have zero overhead compared to doing new and delete manually, which is a good thing. I don't see any immediate flaws in using your own deletions that store this extra pointer, although I still have to face a use case where I would find this useful.

+8
source

shared_ptr has the overhead of link counting. It also stores an explicit deleter in its reference counting unit (because if you store on the heap, what are a few more bytes?)

That is why shared_ptr for the base type can remember the removal of derived types without a virtual dtor.

unique_ptr , on the other hand, saves its debiter in the instance, and the default default - idle - uses 0 bytes. This makes unique_ptr null overhead over the raw pointer regarding memory usage.

Indenting a state without saving cannot forget to delete something else.

You can add a stateful handler to unique_ptr that supports aliasing, but then you will have to execute the alias manually. One of the constructors accepts both a pointer and a delete.

+5
source

Source: https://habr.com/ru/post/1240138/


All Articles