Home > Back-end >  How to construct some classes in a vector?
How to construct some classes in a vector?

Time:08-16

I'm working on a class, and I need to have vector of the class. I would like to have objects constructed in place rather than using copy construction. It seems that use of copy construction is inevitable.

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


class MyData {

public:
    int age;
    std::string name;

    MyData(int age, std::string name) : age(age), name(name)
    {
        std::cout << "MyData::MyData(int, std::string)\n";
    }

    MyData(const MyData& myData) : age(myData.age), name(myData.name)
    {
        std::cout << "MyData::MyData(const MyData&)\n";
    }

    MyData(MyData&& myData)
        :age(std::move(myData.age)), name(std::move(myData.name))
    {
        std::cout << "MyData::MyData(MyData&&)\n";
    }

    ~MyData() {
        std::cout << "MyData::~MyData()\n";
    }

};

#define DEBUG(...) std::cout << "Exec: " #__VA_ARGS__ << ";\n"; __VA_ARGS__ 

int main()
{

    DEBUG(std::vector<MyData> sb1);
    DEBUG(sb1.emplace_back(MyData{ 32, "SJ" }));
    DEBUG(sb1.emplace_back(MyData{ 42, "SJ" }));
}

The output of the code is as follows :

Exec: std::vector<MyData> sb1;
Exec: sb1.emplace_back(MyData{ 32, "SJ" });
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
MyData::~MyData()
Exec: sb1.emplace_back(MyData{ 42, "SJ" });
MyData::MyData(int, std::string)
MyData::MyData(MyData&&)
MyData::MyData(const MyData&)
MyData::~MyData()
MyData::~MyData()
MyData::~MyData()
MyData::~MyData()

C:\Users\XOXOX\source\repos\cpp_stack\x64\Debug\cpp_stack.exe (process 12832) exited with code 0.
Press any key to close this window . . .

I'm using C 2020 and MSVC.

CodePudding user response:

First when you write

DEBUG(sb1.emplace_back(MyData{ 32, "SJ" }));

You create a temporary object that gets passed to the emplaced_back function. The point of emplace_back is that it calls the costructor in-place. So you have to give it the arguments for creating an object, not a temporary object or it will have to use the copy/move constructor.

Second sb1 is a vector with a capacity of 0. So adding items to it will have to resize and that means copying since the move constructor is not noexcept. std::vector can not handle exceptions during a resize so it can't risk using your move constructor.

You should reserve the right side to avoid resize.

CodePudding user response:

You misunderstood what emplace_back does.

It takes the parameters you pass and forwards them to the appropriate constructor.

If you do

sb1.emplace_back(MyData{ 32, "SJ" });

Then the move (or copy) constructor is called. emplace_back cannot magically undo the creation of the temporary. If you want to create the element in place then do not pass a temporary MyData:

sb1.emplace_back(32, "SJ" );

This will call the constructor with int and std::string arguments.

  • Related