Answer the question
In order to leave comments, you need to log in
Assignment operator VS Destructor + Placement new, where placement new argument is prvalue?
Hello everyone
Is it a good practice to use a destructor at address + placement new rather than an assignment operator and a temporary object ?
Example code (here buffer is std::byte):
template<typename ...Args>
void add(Args &&... args)
{
if (size < maxSize)
{
new (&buffer[sizeof(T) * head]) T(std::forward<Args>(args)...);
head = (head + 1) % maxSize;
++size;
return;
}
// Assignment operator
// (*(reinterpret_cast<T *>(&buffer[sizeof(T) * head]))) = T(std::forward<Args>(args)...);
// Destructor + Placement new
int32_t index = sizeof(T) * head;
(reinterpret_cast<T *>(&buffer[index]))->~T();
new (&buffer[index]) T(std::forward<Args>(args)...);
head = (head + 1) % maxSize;
}
Answer the question
In order to leave comments, you need to log in
There are many requirements for modern code. In particular, the code must meet certain quality criteria in order to have a chance of being added to the main repository as a solution to the problem.
Among such quality criteria are often: compliance with the general style of the code, compliance with the general style of formatting, the availability of documentation or self-documenting, as well as elementary clarity for the reader.
The reader of modern code shouldn't have to wonder what the poison gas is doing here, why the mops, and why the fan is so big [ ? ].
The reader should understand everything almost immediately, he should have as few questions as possible.
The reader's questions arise when he sees something illogical specifically for a given section of code.
When the reader examines the code for a circular buffer, he keeps in mind the rule that the elements being added will either be added to unallocated memory, or will replace elements already located in memory.
It is better not to break this logic for the reader, otherwise questions will come up. Therefore, the most logical way would be to replace the state of an already placed object with a new one using the move operator.
*reinterpret_cast<T*>( &buffer[ sizeof( T ) * head ] ) = T{ std::forward<Args>( args )... };
auto T vicar{ std::forward<Args>( args )... };
std::swap( *reinterpret_cast<T*>( &buffer[ sizeof( T ) * head ] ), vicar );
std::swap
, but only from people with little STL habit. T
is non-relocatable. Your central bank must have checks for transferability, copyability, and the possibility of exchanging states. T
you can copy but not move, use the copy operator. T
, you should use a destructor and an allocating constructor. T
only one specific template overload is included for any.
It seems to me that this issue should be considered from the point of view of several positions:
int32_t index = sizeof(T) * head;
(reinterpret_cast<T *>(&buffer[index]))->~T();
new (&buffer[index]) T(std::forward<Args>(args)...);
head = (head + 1) % maxSize;
int32_t index = sizeof(T) * head;
(reinterpret_cast<T *>(&buffer[index]))->~T();
new (&buffer[index]) T(std::forward<Args>(args)...);
head = (head + 1) % maxSize;
// Assignment operator
// (*(reinterpret_cast<T *>(&buffer[sizeof(T) * head]))) = T(std::forward<Args>(args)...);
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question