DummySenior
DummySenior

Reputation: 103

Does the C++ Object not get std::moved?

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

Answers (4)

molbdnilo
molbdnilo

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

SHR
SHR

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

Some programmer dude
Some programmer dude

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

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:

  1. Worker w1 ("Bob");
  2. 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

Related Questions