Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

emplace_back calls move constructor, and destructor

I try to emplace two instance of the class cBar to a vector with emplace_back function.

According to the reference calling an emplace_back only reserve the place in the vector, then create the new instance "in place".

Now, I tried to experiment with it:

#include <vector>
#include <iostream>
#include <memory>
#include <string>


class cBar
{
public:

    cBar(const int index);
    cBar(cBar&& other); //needed for emplace_back?
    ~cBar();

private:
    cBar(const cBar& other) = delete;
    cBar& operator=(const cBar& other) = delete;

public:
    int                         mIndex;

};




cBar::cBar(const int index) : mIndex(index)
{
    std::cout << "cBar being created ..." << std::endl;
}
cBar::cBar(cBar&& other) : mIndex(other.mIndex)
{
    std::cout << "cBar being moved ..." << std::endl;
}
cBar::~cBar()
{
    std::cout << "cBar being destroyed ..." << std::endl;
}

int main()
{
    std::vector<cBar> mBars;

    std::cout << "Begin to create 2 cBar instance, I am expecting 2 \"cBar being created ...\" messages here" << std::endl;
    mBars.emplace_back(0);//this supposed to call only cBar(const int index) constructor, and nothing more
    mBars.emplace_back(1);//this works as expected, only one constructor call

    //destroy all
    std::cout << "Destroy the 2 isntances (this works, I see the two expected \"cBar being destroyed ...\" messages here" << std::endl;
    mBars.clear();

    std::cin.get();
    return 0;
}

Output:

Begin to create 2 cBar instance, I am expecting 2 "cBar being created ..." messages here
cBar being created ...
cBar being moved ...
cBar being destroyed ...
cBar being created ...
Destroy the 2 isntances (this works, I see the two expected "cBar being destroyed ..." messages here
cBar being destroyed ...
cBar being destroyed ...

If you run the one above, you will see that the first emplace_back creates the instance "in place", but then immediately call the move constructor, and then destructor is called.

What is more strange, that in case of the second emplace, I see the expected behavior: Only one constructor call.

I have two questions:

  1. Why do I need to define a move constructor in my class if I just want to emplace_back items, and never use push_back.

  2. In case of the first instance creation, why the move constructor, then the destructor is called? If I access the data of the first instance all seems to correct, so I have no idea why the move constructor, and destructor is called.

I use Visual Studio 2015.

Output with vector sizes in each step:

Begin to create 2 cBar instance, I am expecting 2 "cBar being created ..." messages here
Vector size:0
cBar being created ...
Vector size:1
cBar being moved ...
cBar being destroyed ...
cBar being created ...
Vector size:2
Destroy the 2 isntances (this works, I see the two expected "cBar being destroyed ..." messages here
cBar being destroyed ...
cBar being destroyed ...
like image 951
Avi Avatar asked Apr 02 '17 13:04

Avi


People also ask

Does Emplace_back call copy constructor?

So you can emplace_back does use the desired constructor to create the element and call copy constructor when it need to grow the storage.

Does Emplace_back copy or move?

Calling emplace_back will call the move constructor of std::string when std::move is used, which could save on a copy (so long as that string isn't stored in a SSO buffer). Note that this is essentially the same as push_back in this case.

What is the function of Emplace_back?

C++ Vector Library - emplace_back() Function The C++ function std::vector::emplace_back() inserts new element at the end of vector. Reallocation happens if there is need of more space. This method increases container size by one.

Should I use Push_back or Emplace_back?

Specific use case for emplace_back : If you need to create a temporary object which will then be pushed into a container, use emplace_back instead of push_back . It will create the object in-place within the container. Notes: push_back in the above case will create a temporary object and move it into the container.


2 Answers

2.In case of the first instance creation, why the move constructor, then the destructor is called?

Because the insertion of the 2nd element by emplace_back causes the reallocation; the inner storage of the vector needs to be extended, the elements in the old storage have to be copied/moved to the new storage, then destroyed.

You can use reserve in advance to avoid reallocation.

1.Why do I need to define a move constructor in my class if I just want to emplace_back items, and never use push_back.

As the above explanation said, vector needs to move elements by copy/move operation. So you have to define the copy or move constructor for the class. This is true for both emplace_back and push_back, because they both add elements to vector and might cause reallocation.

like image 75
songyuanyao Avatar answered Oct 24 '22 03:10

songyuanyao


Odds are the capacity of your vector was one, and when you put the second element in, it had to resize the vector. That can turn into a bunch of things being moved in memory, and the symptoms you see.

Kerreks advice is good. I suggest printing the vectors capacity before and after each operation to see if the capacity change is the cause.

like image 34
EvilTeach Avatar answered Oct 24 '22 05:10

EvilTeach