Conversión de std:: unique ptr a std:: unique ptr


Digamos que tengo funciones de fábrica que tratan con clases base y derivadas:

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

En la última línea de arriba, necesito move(d) para que funcione, de lo contrario obtengo "Error: invalid conversion from std::unique_ptr<D> to std::unique_ptr<D>&&."Mi intuición decía que en este contexto, el compilador debería saber que implícitamente podría hacer d un rvalue y moverlo al puntero base, pero no lo hace.

¿Es esto una no conformidad en mis compiladores (gcc 4.8.1 y VS2012)? El diseño previsto de unique_ptr? ¿Un defecto en el estándar?

Author: metal, 2014-02-25

2 answers

El comportamiento del compilador es correcto. Solo hay un movimiento implícito cuando los tipos son los mismos, porque el movimiento implícito se especifica en términos de que el compilador no realiza la elisión de copia en los casos en que realmente se permite (ver 12.8/31 y 12.8/32).

12.8 / 31 (copia elision):

En una sentencia return en una función con una clase return type, cuando la expresión es el nombre de un objeto automático no volátil (que no sea un parámetro function o catch-clause) con el mismo tipo cv-unqualified que la función devuelve el tipo...

12.8 / 32 (movimiento implícito):

Cuando se cumplen los criterios para la elisión de una operación de copia, [...], la resolución de sobrecarga para seleccionar el constructor para la copia se realiza primero como si el objeto fuera designado por un rvalue.

 33
Author: Simple,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-25 15:19:41

Con la adición de las llamadas std::move en las sentencias return, este código funciona para mí en Visual Studio 2013:

#include <memory>

using namespace std;

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

unique_ptr<B> MakeB()
{
  auto b = unique_ptr<B>( new B() );
  return std::move( b );  // *** std::move() added here! ***
}

unique_ptr<B> MakeD()
{
  auto d = unique_ptr<D>( new D() );
  return std::move( d );  // *** std::move() added here! ***
}

Lo siguiente también funciona

unique_ptr<B> MakeB()
{
  return unique_ptr<B>( new B() );  // *** Returning a temporary! ***
}

unique_ptr<B> MakeD()
{
  return unique_ptr<D>( new D() );  // *** Returning a temporary! ***
}

Por supuesto, si estás regresando std::unique_ptr<B> de todos modos, ¿por qué no meter la instancia D en una std::unique_ptr<B> en primer lugar? Entonces no hay conversión necesaria en absoluto!

 -4
Author: aldo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-25 17:19:55