Как передать std::unique_ptr
в функцию? Допустим, у меня есть следующий класс:
class A
{
public:
A(int val)
{
_val = val;
}
int GetVal() { return _val; }
private:
int _val;
};
Следующее не компилируется:
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;
}
Почему я не могу передать std::unique_ptr
в функцию? Конечно, это основная цель конструкции? Или комитет C ++ намеревался, чтобы я вернулся к необработанным указателям в стиле C и передал их следующим образом:
MyFunc(&(*ptr));
И что самое странное, почему это нормальный способ передать это? Это кажется ужасно непоследовательным:
MyFunc(unique_ptr<A>(new A(1234)));
c++
c++11
unique-ptr
user3690202
источник
источник
Ответы:
Здесь есть два основных варианта:
Передайте умный указатель по ссылке
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); }
Переместите умный указатель в аргумент функции
Обратите внимание, что в этом случае утверждение будет выполнено!
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) }
источник
unique_ptr
по ссылке только в том случае, если функция может или не может перемещаться от нее. И тогда это должна быть ссылка на rvalue. Чтобы наблюдать за объектом, не требуя ничего о семантике его владения, используйте ссылку, напримерA const&
илиA&
.ptr
будет после переезда.Вы передаете его по значению, что подразумевает создание копии. Это было бы не очень уникально, не так ли?
Вы можете переместить значение, но это подразумевает передачу права собственности на объект и управления его временем жизни функции.
Если время жизни объекта гарантированно существует в течение времени жизни вызова MyFunc, просто передайте необработанный указатель через
ptr.get()
.источник
Вы не можете этого сделать, потому что у вас
unique_ptr
есть конструктор перемещения, но нет конструктора копирования. Согласно стандарту, когда конструктор перемещения определен, но конструктор копирования не определен, конструктор копирования удаляется.Вы можете передать
unique_ptr
функцию, используя:void MyFunc(std::unique_ptr<A>& arg) { cout << arg->GetVal() << endl; }
и используйте его, как будто у вас есть:
или
void MyFunc(std::unique_ptr<A> arg) { cout << arg->GetVal() << endl; }
и используйте его как:
std::unique_ptr<A> ptr = std::unique_ptr<A>(new A(1234)); MyFunc(std::move(ptr));
Важная заметка
Обратите внимание, что если вы используете второй метод,
ptr
он не владеет указателем после вызова функцииstd::move(ptr)
возврата.void MyFunc(std::unique_ptr<A>&& arg)
будет иметь такой же эффект,void MyFunc(std::unique_ptr<A>& arg)
поскольку оба являются ссылками.В первом случае
ptr
все еще остается владельцем указателя после вызоваMyFunc
.источник
Поскольку
MyFunc
не принимает права собственности, было бы лучше иметь:void MyFunc(const A* arg) { assert(arg != nullptr); // or throw ? cout << arg->GetVal() << endl; }
или лучше
void MyFunc(const A& arg) { cout << arg.GetVal() << endl; }
Если вы действительно хотите стать владельцем, вам нужно переместить свой ресурс:
std::unique_ptr<A> ptr = std::make_unique<A>(1234); MyFunc(std::move(ptr));
или передайте напрямую ссылку на r-значение:
MyFunc(std::make_unique<A>(1234));
std::unique_ptr
не имеет копии специально, чтобы гарантировать наличие только одного владельца.источник
ptr.get()
или просто передаетеptr
в функцию?MyFunc
для передачи ссылки на r-значение?void MyFunc(A&& arg)
берет ссылку на r-значение ...typedef int A[]
,MyFunc(std::make_unique<A>(N))
дает ошибку компилятора: error: неверная инициализация ссылки типа 'int (&&) []' из выражения типа 'std :: _ MakeUniq <int []> :: __ array' { aka 'std :: unique_ptr <int [], std :: default_delete <int []>>'}g++ -std=gnu++11
Достаточно недавно?Вы можете, но не копированием - потому что
std::unique_ptr<>
это не копируемо.Среди прочего,
std::unique_ptr<>
он предназначен для однозначной маркировки уникального владения (в отличие отstd::shared_ptr<>
).Потому что в этом случае нет конструкции копирования.
источник
Поскольку
unique_ptr
для уникального владения, если вы хотите передать его в качестве аргумента, попробуйтеНо после того, что состояние
ptr
инmain
будетnullptr
.источник
unique_ptr
будет бесполезным.Передача в
std::unique_ptr<T>
качестве значения функции не работает, потому что, как вы, ребята, упомянули,unique_ptr
ее нельзя скопировать.Как насчет этого?
std::unique_ptr<T> getSomething() { auto ptr = std::make_unique<T>(); return ptr; }
этот код работает
источник