I'm trying to return a vector<unique_ptr>
from a function, but I'm running into errors. I'm using MSVC 19.33.31630.
The comments to this question recommend returning by value, but this code:
std::vector<std::unique_ptr<int>> test1()
{
std::vector<std::unique_ptr<int>> ret = { std::make_unique<int>(1) };
return ret;
}
int main()
{
std::vector<std::unique_ptr<int>> x = test1();
std::unique_ptr<int>& ptrY = x.at(0);
return 0;
}
yields this error:
Error C2280 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function
Returning by reference, as in this code:
std::vector<std::unique_ptr<int>>& test2()
{
std::vector<std::unique_ptr<int>> ret = { std::make_unique<int>(1) };
return ret;
}
int main()
{
std::vector<std::unique_ptr<int>>& y = test2();
std::cout << *(y.at(0)) << std::endl;
return 0;
}
yields the same error.
Why is this happening? Is the ownership of the unique_ptr
not transferring properly?
CodePudding user response:
Thanks @user4581301 for answering this in the comments. As best as I can tell:
- test2() puts the std::vector on the stack which goes out of scope.
- test1() ends up copying the unique_ptr into an initializer_list
The solution is to return by value, and initialize the vector with push_back/emplace_back instead of an initializer_list:
std::vector<std::unique_ptr<int>> test3()
{
std::vector<std::unique_ptr<int>> ret;
ret.push_back(std::make_unique<int>(1));
return ret;
}
int main()
{
std::vector<std::unique_ptr<int>> x = test3();
std::unique_ptr<int>& ptrY = x.at(0);
std::cout << *ptrY;
return 0;
}
CodePudding user response:
std::vector<std::unique_ptr<int>> x = test1();
You're making a copy of the vector that test1
returns here, which in turn needs to copy all its content. That's what an assignment operator =
does by default! Only after the copy is done, the return value of test1
will run out of scope and get destructed.
You're trying to copy unique_ptr
s; can't copy a unique_ptr
. So, this is correct.
Use std::move
to move the values held by the vector.
Even better, don't use the assignment operator, but construct from the return value directly, which will use the move constructor (if the function returns by value).