¿Cómo puedo pasar una std::unique_ptr
a una función? Digamos que tengo la siguiente clase:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Lo siguiente no se compila:
void MyFunc(unique_ptr<A> arg)
{
cout << arg->GetVal() << endl;
}
int main(int argc, char* argv[])
{
unique_ptr<A> ptr = unique_ptr<A>(new A(1234));
MyFunc(ptr);
return 0;
}
¿Por qué no puedo pasar una std::unique_ptr
a una función? ¿Seguramente este es el propósito principal del constructo? ¿O el comité de C ++ tenía la intención de que recurriera a punteros de estilo C sin formato y lo pasara así:
MyFunc(&(*ptr));
Y lo más extraño de todo, ¿por qué es una buena forma de pasarlo? Parece horriblemente inconsistente:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
user3690202
fuente
fuente
Respuestas:
Básicamente, hay dos opciones aquí:
Pase el puntero inteligente por referencia
void MyFunc(unique_ptr<A> & arg) { cout << arg->GetVal() << endl; } int main(int argc, char* argv[]) { unique_ptr<A> ptr = unique_ptr<A>(new A(1234)); MyFunc(ptr); }
Mueva el puntero inteligente al argumento de la función
Tenga en cuenta que en este caso, la aserción se mantendrá.
void MyFunc(unique_ptr<A> arg) { cout << arg->GetVal() << endl; } int main(int argc, char* argv[]) { unique_ptr<A> ptr = unique_ptr<A>(new A(1234)); MyFunc(move(ptr)); assert(ptr == nullptr) }
fuente
unique_ptr
por referencia si la función puede o no moverse de él. Y luego debería ser una referencia rvalue. Para observar un objeto sin requerir nada sobre su semántica de propiedad, use una referencia comoA const&
oA&
.ptr
después de la mudanza.Lo estás pasando por valor, lo que implica hacer una copia. Eso no sería muy especial, ¿verdad?
Puede mover el valor, pero eso implica pasar la propiedad del objeto y el control de su vida útil a la función.
Si se garantiza que la vida útil del objeto existe durante la vida útil de la llamada a MyFunc, simplemente pase un puntero sin procesar a través de
ptr.get()
.fuente
No puede hacer eso porque
unique_ptr
tiene un constructor de movimiento pero no un constructor de copia. De acuerdo con el estándar, cuando se define un constructor de movimiento pero no se define un constructor de copia, se elimina el constructor de copia.Puede pasar el
unique_ptr
a la función usando:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
y úsalo como lo has hecho:
o
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
y utilícelo como:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Nota IMPORTANTE
Tenga en cuenta que si utiliza el segundo método,
ptr
no tiene la propiedad del puntero después de la llamada astd::move(ptr)
devoluciones.void MyFunc(std::unique_ptr<A>&& arg)
tendría el mismo efecto quevoid MyFunc(std::unique_ptr<A>& arg)
ya que ambos son referencias.En el primer caso,
ptr
todavía tiene la propiedad del puntero después de la llamada aMyFunc
.fuente
Como
MyFunc
no se apropia, sería mejor tener:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
o mejor
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Si realmente desea tomar posesión, debe mover su recurso:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
o pasar directamente una referencia de valor r:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
no tiene copia a propósito para garantizar tener un solo dueño.fuente
ptr.get()
o simplemente pasando elptr
a la función?MyFunc
para pasar una referencia de valor r?void MyFunc(A&& arg)
toma la referencia de valor r ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
da el error del compilador: error: inicialización no válida de la referencia del tipo 'int (&&) []' de la expresión del tipo 'std :: _ MakeUniq <int []> :: __ array' { también conocido como 'std :: unique_ptr <int [], std :: default_delete <int []>>'} ¿Es log++ -std=gnu++11
suficientemente reciente?Puede hacerlo, pero no por copia, porque
std::unique_ptr<>
no se puede copiar.Entre otras cosas,
std::unique_ptr<>
está diseñado para marcar inequívocamente la propiedad única (a diferencia destd::shared_ptr<>
).Porque en ese caso, no hay construcción de copias.
fuente
Dado que
unique_ptr
es para propiedad única, si desea pasarlo como argumento, intentePero después de eso, el estado de
ptr
inmain
seránullptr
.fuente
unique_ptr
sería bastante inútil.Pasar
std::unique_ptr<T>
como valor a una función no funciona porque, como ustedes mencionan,unique_ptr
no se puede copiar.¿Qué pasa con esto?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
este código está funcionando
fuente