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.