Como posso passar um std::unique_ptr
em uma função? Digamos que eu tenha a seguinte aula:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
O seguinte não 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 que não posso passar um std::unique_ptr
para uma função? Certamente este é o objetivo principal do construto? Ou o comitê de C ++ pretendia que eu voltasse às dicas de estilo C brutas e as passasse assim:
MyFunc(&(*ptr));
E o mais estranho de tudo, por que essa é uma maneira OK de passar isso? Parece terrivelmente inconsistente:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
user3690202
fonte
fonte
Respostas:
Existem basicamente duas opções aqui:
Passe o ponteiro inteligente por referência
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); }
Mova o ponteiro inteligente para o argumento da função
Observe que, neste caso, a declaração será válida!
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) }
fonte
unique_ptr
por referência se a função puder ou não sair dele. E então deve ser uma referência de rvalue. Para observar um objeto sem exigir nada sobre sua semântica de propriedade, use uma referência comoA const&
ouA&
.ptr
após a mudança.Você está passando por valor, o que implica fazer uma cópia. Isso não seria muito original, seria?
Você pode mover o valor, mas isso implica passar a propriedade do objeto e o controle de sua vida útil para a função.
Se for garantido que o tempo de vida do objeto existirá durante o tempo de vida da chamada para MyFunc, basta passar um ponteiro bruto via
ptr.get()
.fonte
Você não pode fazer isso porque
unique_ptr
tem um construtor de movimento, mas não um construtor de cópia. De acordo com o padrão, quando um construtor de movimento é definido, mas um construtor de cópia não é definido, o construtor de cópia é excluído.Você pode passar o
unique_ptr
para a função usando:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
e use-o como você fez:
ou
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
e usá-lo como:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Nota importante
Observe que se você usar o segundo método,
ptr
não tem propriedade do ponteiro após a chamada parastd::move(ptr)
retorna.void MyFunc(std::unique_ptr<A>&& arg)
teria o mesmo efeito,void MyFunc(std::unique_ptr<A>& arg)
já que ambos são referências.No primeiro caso,
ptr
ainda tem propriedade do ponteiro após a chamada paraMyFunc
.fonte
Como
MyFunc
não se apropria, seria melhor ter:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
ou melhor
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Se você realmente deseja assumir a propriedade, deverá mover seu recurso:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
ou passe diretamente uma referência de valor r:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
não possui cópia proposital para garantia de ter apenas um proprietário.fonte
ptr.get()
ou apenas passando optr
para a função?MyFunc
para passar uma referência de valor r?void MyFunc(A&& arg)
leva a referência do valor r ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
dá o erro do compilador: erro: inicialização inválida de referência do tipo 'int (&&) []' da expressão do tipo 'std :: _ MakeUniq <int []> :: __ array' { aka 'std :: unique_ptr <int [], std :: default_delete <int []>>'} Ég++ -std=gnu++11
recente o suficiente?Você pode, mas não por cópia - porque
std::unique_ptr<>
não é construtível por cópia.Entre outras coisas,
std::unique_ptr<>
é projetado para marcar inequivocamente a propriedade única (em oposição astd::shared_ptr<>
).Porque, nesse caso, não há construção de cópia.
fonte
Uma vez que
unique_ptr
é de propriedade única, se você quiser passar como argumento tenteMas depois disso, o estado de
ptr
emmain
seránullptr
.fonte
unique_ptr
será bastante inútil.Passar
std::unique_ptr<T>
como valor para uma função não está funcionando porque, como vocês mencionaram,unique_ptr
não é copiável.Que tal isso?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
este código está funcionando
fonte