Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't std::unique_ptr have an aliasing constructor like std::shared_ptr has?

Tags:

c++

c++11

I've just discovered std::shared_ptr's "aliasing constructor" and find myself asking "why doesn't std::unique_ptr have an corresponding one?

That is, if you want to allocate a Foo so that you can pass its Bar member to a function that should entirely manage the lifetime of the Foo, wouldn't it be nice to be able to do so?

#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;
}

outputs 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 wasn't included? And/or, is it a bad idea to emulate it with a unique_ptr<B> with a custom deleter that deletes the A?

like image 547
Rob Starling Avatar asked Jan 08 '16 03:01

Rob Starling


People also ask

Can you convert shared_ptr to unique_ptr?

In short, you can easily and efficiently convert a std::unique_ptr to std::shared_ptr but you cannot convert std::shared_ptr to std::unique_ptr .

In what situation is a shared_ptr more appropriate than a unique_ptr?

Use unique_ptr when if you want to have single ownership(Exclusive) of resource. Only one unique_ptr can point to one resource. Since there can be one unique_ptr for single resource its not possible to copy one unique_ptr to another. Use shared_ptr if you want to share ownership of resource .

What is the use of std :: unique_ptr?

std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.

Can unique_ptr be copied?

A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.


1 Answers

I believe the “problem” is that, unlike std::shared_ptr, std::unique_ptr's deleter is not type-erased. The default deleter of std::unique_ptr<T> (which has zero size, encoded into the type itself as a barely visible default type parameter) is simply [](T * p){ delete p; }. But it is clear that a std::unique_ptr<B> that was created via std::make_unique<B> and one that was made by pointing to a B member of an A object cannot have the same deleter. The deleter for the latter case would have to do some pointer arithmetic to obtain the original A * pointer back. Those two deleters could only have the same type if both would store an offset or an internal pointer to the original object. And that would 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 drawbacks from using your own deleters that store that additional pointer, though I'd still have to come across a use-case where I'd find this useful.

like image 112
5gon12eder Avatar answered Oct 22 '22 22:10

5gon12eder