Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting std::unique_ptr<Derived> to std::unique_ptr<Base>

Using C++11, let's say I have factory functions dealing with base and derived classes:

#include <memory>

using namespace std;

struct B { virtual ~B() {} };
struct D : B {};

unique_ptr<B> MakeB()
{
    auto b = unique_ptr<B>( new B() );
    return b; // Ok!
}

unique_ptr<B> MakeD()
{
    auto d = unique_ptr<D>( new D() );
    return d; // Doh!
}

On the last line above, I need move(d) in order to make it work, otherwise I get "Error: invalid conversion from std::unique_ptr<D> to std::unique_ptr<D>&&." My intuition said that in this context, the compiler should know that it could implicitly make d an rvalue and move it into the base pointer, but it doesn't.

Is this a non-conformancy in my compilers (gcc 4.8.1 and VS2012)? The intended design of unique_ptr? A defect in the standard?


Update: C++14 fixes this. Newer compilers such as GCC 9 accept the original code even with -std=c++11.

like image 920
metal Avatar asked Feb 25 '14 15:02

metal


People also ask

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.

What happens when unique_ptr goes out of scope?

unique_ptr. An​ unique_ptr has exclusive ownership of the object it points to and ​will destroy the object when the pointer goes out of scope.

What is 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.

How do I pass a unique_ptr argument to a constructor or a function?

You cannot copy a unique_ptr . You can only move it. The proper way to do this is with the std::move standard library function. If you take a unique_ptr by value, you can move from it freely.


1 Answers

The compiler's behaviour is correct. There is only an implicit move when the types are the same, because implicit move is specified in terms of the compiler failing to perform copy elision in cases where it is actually allowed (see 12.8/31 and 12.8/32).

12.8/31 (copy elision):

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type...

12.8/32 (implicit move):

When the criteria for elision of a copy operation are met, [...], overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

like image 114
Simple Avatar answered Oct 13 '22 12:10

Simple