I have following c code. You can see I created a struct with a constructor and a copy constructor. Can someone explain me why copy constructor is being invoked for the first assignment and not for the other 2 assignments?
#include <iostream>
#include <string>
#include <vector>
struct Vertex
{
float x, y, z;
Vertex(float x, float y, float z)
: x(x), y(y), z(z)
{
std::cout << "Created Vertex!" << std::endl;
}
Vertex(const Vertex& v) // Copy constructor
: x(v.x), y(v.y), z(v.z)
{
std::cout << "Copied!" << std::endl;
}
};
std::ostream& operator<<(std::ostream& stream, const Vertex& _v) // Overloading operator<<
{
stream << _v.x << ", " << _v.y << ", " << _v.z;
return stream;
}
int main()
{
std::vector<Vertex> vertices;
vertices.reserve(3);
vertices.emplace_back(Vertex(1, 2, 3)); // 1st assignment
vertices.emplace_back(4, 5, 6);
vertices.emplace_back(7, 8, 9);
return 0;
}
CodePudding user response:
From the the reference for emplace_back
Appends a new element to the end of the container. The element is constructed through std::allocator_traits::construct, which typically uses placement-new to construct the element in-place at the location provided by the container.
As you can see in the example on the c reference page, emplace_back
can be used to avoid copy and move constructors of the object to be created (though, the parameters of these constructors are still moved or copied --- in your case, being such parameters PODs, no copy/move of parameters is present).
But in your first call, you create the object by calling explicitly Vertex(1,2,3)
.
Then you pass this variable to emplace_back
to create a new object.
Generally, for this purpose you would prefer to "move" the object to the vector, that is, to use the move constructor.
But, since you have defined a copy construct, an implicitly-declared move constructor is not available. Hence the compiler has to fall back to your copy constructor to insert the element Vertex(1,2,3)
into the vector.
CodePudding user response:
The argument(s) you give when you call emplace_back
are forwarded to the relevant constructor for the type of object that the vector contains. In your first call, the argument you give is Vertex(1,2,3)
; that makes an explicit call to the constructor takings three float
arguments, then passes the constructed object as the actual argument to emplace_back
. Thus, the relevant constructor to be called is the copy constructor.
In the other two calls, the arguments given correspond to those for the 'plain' constructor, so that is the one chosen for those calls.