-2

“Downcasting” unique_ptr< Base > to unique_ptr< Derived > offer an elegent solution to downcasting unique_ptr. It works in most of time. But when the Derived contains unique_ptr, something go wrong:

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
static_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    auto d = static_cast<Derived *>(p.release());
    return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
} 

struct Data
{
   int data;
};

struct Base
{
};

struct Derived : public Base
{
    Derived() 
        : data(std::make_unique<Data>())

    std::unique_ptr<Data> data;
};

int main()
{
    std::unique_ptr<Base> base = std::make_unique<Derived>();

    auto data = static_unique_ptr_case<Derived>(std::move(base))->data; // compile error

    return 0;
}

Is there a better way to fix the problem?

Eidt:

fix the typos and

@Igor Tandetnik give a solution

std::unique_ptr<Base> base = std::make_unique<Derived>();

//auto& data = static_unique_ptr_case<Derived>(std::move(base))->data; // compile error

auto derived = static_unique_ptr_case<Derived>(std::move(base));

auto& data = derived->data;

return 0;
foo
  • 398
  • 1
  • 16
  • 2
    Apart from typos (`Derived` constructor not being properly defined, missing `;`, etc), the problem is because `std::unique_ptr` has an explicitly `delete`d copy constructor, and the offending error is because of an attempt to copy construct a `std::unique_ptr`. Without knowing WHY you expect copy constructing a `std::unique_ptr` to work - since by design it does not - nobody can really help you. – Peter Dec 26 '18 at 03:59
  • 1
    Your program boils down to `std::unique_ptr data; auto derived = data;` The failure has nothing to do with `static_unique_ptr_cast`. After fixing numerous obvious typos, [this code compiles](https://ideone.com/W6Ds0p) – Igor Tandetnik Dec 26 '18 at 04:19
  • @ Igor Tandetnik Thank you. I see. – foo Dec 26 '18 at 04:25

1 Answers1

0

The online documentation states this about unique_ptr:

The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.

So you cannot copy construct or copy assign a unique_ptr as you are trying to do in the line:

auto derived = static_unique_ptr_cast<Derived>(std::move(base))->data; // compile error
P.W
  • 26,289
  • 6
  • 39
  • 76