Reputation: 103
I got the following code: (Code Live: C++ Shell)
class Worker
{
public:
Worker (std::string name):_name (name) {};
Worker (const Worker & worker):_name (worker._name)
{ std::cout << _name << " got copied!" << std::endl; }
Worker (Worker && other):_name (other._name)
{ std::cout << _name << " got moved!" << std::endl; }
~Worker ()
{ std::cout << _name << " got destroyed!" << std::endl; }
void changeName(std::string name)
{ this->_name = name; }
private:
std::string _name;
};
class Factory
{
public:
Factory ()
{ std::cout << "Factory got created!" << std::endl; }
~Factory ()
{ std::cout << "Factory got destroyed!" << std::endl; }
void addWorker (Worker & worker)
{ this->workers.push_back (std::move (worker)); }
Worker & getLastWorker ()
{ this->workers.back (); }
private:
std::vector < Worker > workers;
};
int main ()
{
auto factory = std::make_unique < Factory > ();
Worker w1 ("Bob");
factory->addWorker (w1);
Worker & workerRef = factory->getLastWorker ();
//workerRef.changeName("Mary");
return 0;
}
Where I have a Factory
storing at its Workers
in a vector. When I run the main()
I get the following output:
Factory got created!
Bob got moved!
Bob got destroyed!
Factory got destroyed!
Bob got destroyed!
But I can't get my head around why Bob got destroyed!
appears two times, as I thought Worker w1
gets moved to the vector workers
in the Factory
. Additionally, if you comment in workerRef.changeName("Mary");
the code crashes with Segmentation fault
.
I'm coding with c++ for a month now and really struggle here. I have googled quite for a while, but can't find a hint, so any help is great!
Upvotes: 4
Views: 318
Reputation: 66371
You still have two objects, one in main
and one inside the vector.
"Moving" doesn't actually move an object, only its contents - at least conceptually (std::move
is only a type cast).
It's not necessarily the case that anything moves at all, like in your case, where the "move constructor" behaves exactly like a copy constructor.
If you want a more "move-y" move constructor, you should write :_name (std::move(other._name))
, which will make w1
's name empty.
The reason for the crash is that you forgot to write return
in getLastWorker
.
Increase the warning level on your compiler and pay attention to it.
Upvotes: 5
Reputation: 8313
It is simple:
An empty object destructor is also called.
In move constractor
the old object transfers its content (especially pointers) to the new one, and become empty, then it been destroyed at the end of scope as an empty object.
Take a notice that after the move constructor the original shouldn't have called Bob anymore...
Upvotes: 0
Reputation: 409166
First of all, your move-constructor doesn't really move anything, it just copies the string.
And as you push back the Worker
into the vector you still have two Worker
objects: One in the main
function and one inside the vector. Both of these objects needs to be destructed.
Upvotes: 1
Reputation: 170055
Moving only moves the contents of objects (if implemented like that, it could just copy). It doesn't mean the original object vanishes, only that its value possibly changes.
Your example creates two objects in two places:
Worker w1 ("Bob");
this->workers.push_back (std::move (worker));
The second steals the guts from the first (on the face of it, anyway), but the first is still alive. And any living object will have its destructor called at the end of its lifetime (for w1
it's the closing of main
).
Upvotes: 7