Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Aggregate initialization inside emplace_back

In the following code, I am trying to use aggregate initialization with emplace_back. The catch here is that emplace_back takes the constructor arguments and constructs the object directly in the vector, and I want to know whether the copy constructor is called on a A{1,2,3} or not. However, for aggregate initialization to work, the struct should not have a user-defined constructor. Any ideas what’s happening behind the scenes?

#include <iostream>
#include <vector>

struct A {
    int x, y, z;
    /*A(int x, int y, int z) : x(x), y(y), z(z) 
    {
        std::cout << "ctor called\n";
    }
    A(const A& other) : x(other.x), y(other.y), z(other.z) {
        std::cout << "copy ctor called\n";
    }*/
};

int main() {

    std::vector<A> vec;

    vec.emplace_back(A{1, 2, 3});

    return 0;
}

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

emplace_back will construct the object directly in the vector, as you’ve said. However, you’ve already constructed a temporary object A{1, 2, 3} at the call site, so that object in the vector will be copy/move constructed, and there are two objects in total. Note that:

  • aggregate types don’t have a constructor that initializes their members to a list of parameter, but they have implicitly-defined copy/move constructors if possible
  • A{1, 2, 3} isn’t calling any constructor; it performs aggregate initialization

This expression A{1, 2, 3} is a prvalue, and will be passed by rvalue reference to emplace_back. Then, the implicitly-defined move constructor of A is going to be called, not the copy constructor.

Providing a copy constructor undeclares the move constructor

If you uncomment the copy constructor in your code, then the copy constructor is called because the move constructor is not declared. You would have to add:

A(A&&) = default;

Then, the move constructor will be called, not the copy constructor. Furthermore, defining this constructor makes the type non-aggregate, so you now need to define a constructor A(int, int, int) because aggregate initialization is no longer possible.

Note on C++20

In C++20, you can initialize aggregates using parentheses as well. This allows you to use emplace_back as if A had a constructor A(int, int, int):

struct A {
    int x, y, z;
};

std::vector<A> vec;
vec.emplace_back(1, 2, 3);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading