I was trying to implement an emplace_back
method for a statically-sized array
(for fun).
I came across the problem of whether I should use placement-new
or move assignment
for this emplace back method.
I have a class point
that is meant to represent some generic class that has a non-trivial move assignment operator, copy assignment operator, move constructor, copy constructor AND default constructor
. Each of these operators/constructors
output a unique string to signify it has been called.
#include <utility>
#include <cstdio>
#include <new>
struct point{
int X; int Y;
point(): X(0), Y(0) {
printf("D ");
}
point(int X, int Y): X(X), Y(Y) {
printf("P ");
}
point(const point& Point): X(Point.X), Y(Point.Y) {
printf("C ");
}
point(point&& Point): X(Point.X), Y(Point.Y) {
printf("M ");
}
point& operator=(const point& Point){
X=Point.X;
Y=Point.Y;
printf("CA ");
return *this;
}
point& operator=(point&& Point){
X=Point.X;
Y=Point.Y;
printf("MA ");
return *this;
}
~point(){
printf("DS ");
}
};
I have a template class
array
that accepts a generic type element
and stores a static array of elements.
For this array class, I have implemented two versions of emplace_back
for a static array:
- One called
EmplaceBackMA
that calls the constructor ofelement
then move assigns the instance of element to the front of the array - Another called
EmplaceBackPN
that calls the destructor of the element at the front of the array then uses placement new to instantiate a new instance ofelement
at the front of the array.
template <typename element>
struct array {
public:
element Buffer[10];
size_t Size = 0;
public:
template<typename... ctorargs>
void EmplaceBackMA(ctorargs&&... Args){
Buffer[Size] = element(std::forward<ctorargs>(Args)...);
++Size;
}
template<typename... ctorargs>
void EmplaceBackPN(ctorargs&&... Args){
Buffer[Size].~element();
new(Buffer + Size) element(std::forward<ctorargs>(Args)...);
++Size;
}
};
Upon testing both EmplaceBack
implementations with the following code, i received the following output.
int main(){
puts("Creating Particles");
array<point> Particles; //DDDDDDDDDD
puts("EmplaceBack");
Particles.EmplaceBackC(4, 4);
puts("\nEmplaceBackMA");
Particles.EmplaceBackMA(4, 4); //P MA DS
puts("\nEmplaceBackPN");
Particles.EmplaceBackPN(4, 4); //DS P
puts("\nEndingProgram");
//Is Placement New Better?
}
Output:
Creating Particles
D D D D D D D D D D
EmplaceBackMA
P MA DS
EmplaceBackPN
DS P
EndingProgram
DS DS DS DS DS DS DS DS DS DS
It seems that Placement New avoids creating a temporary instance of point
so should probably be faster and probably better to use than Move Assignment.
My Question is: Is there a reason to prefer move assignment over placement new for the EmplaceBack method.
I will accept no
or yes with a reason
as an answer.
Following one of the comments, a new emplace back method, EmplaceBackC
has been implemented that checks a class if nothrow constructible
, before using EmplaceBackPN. Is there any other caveat for using Placement New is the EmplaceBackPN
perfectly valid?