I would like to move a unique_ptr<Foo>
out of a vector<unique_ptr<Foo>>
. Consider my code:
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
class Foo {
public:
int x;
Foo(int x): x(x) {};
~Foo() {
cout << "Destroy of id: " << x << "\n";
x = -1;
};
};
int main(int argc, char *argv[]) {
auto foos = vector<unique_ptr<Foo>>();
foos.push_back(unique_ptr<Foo>(new Foo(100)));
foos.push_back(unique_ptr<Foo>(new Foo(101)));
foos.push_back(unique_ptr<Foo>(new Foo(102)));
// Print all
cout << "Vector size: " << foos.size() << "\n";
for (auto i = foos.begin(); i != foos.end(); ++i) {
cout << (*i)->x << "\n";
}
// Move Foo(100) out of the vector
{
auto local = move(foos.at(0));
cout << "Removed element: " << local->x << "\n";
}
// Print all! Fine right?
cout << "Vector size: " << foos.size() << "\n";
for (auto i = foos.begin(); i != foos.end(); ++i) {
cout << (*i)->x << "\n";
}
return 0;
}
I expected that it would yield:
Vector size: 3
100
101
102
Removed element: 100
Destroy of id: 100
Vector size: 2
101
102
But instead, I get this result:
Vector size: 3
100
101
102
Removed element: 100
Destroy of id: 100
Vector size: 3
Segmentation fault: 11
Why is my vector size still 3, and why am I getting a segmentation fault? How can I get my desired result?
Let's simplify your question down to:
vector<unique_ptr<Foo>> foos;
foos.push_back(unique_ptr<Foo>(new Foo(100)));
auto local = std::move(foos[0]);
std::cout << foos[0]->x << '\n';
After you create local
by moving foos[0]
, foos[0]
no longer has ownership of a pointer. It is empty. Dereferencing it becomes undefined behavior, which in your case exhibits as a segmentation fault. The vector
is perfectly "intact" at this point, it contains one empty unique_ptr
, and is equivalently in the state:
vector<unique_ptr<Foo>> foos(1);
You should simply check that your unique_ptr
owns a pointer before dereferencing it:
if (foos[0]) {
// we wouldn't get here
std::cout << foos[0]->x << '\n';
}
Alternatively, since you want to enforce the invariant that your vector
only contains valid pointers, as part of your move-from operation you should just erase
that element:
auto local = std::move(foos[0]);
foos.erase(foos.begin());
// now foos is empty
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With