How standard-compliant is to allocate row memory for an array and then call the assignment operator on the objects from that array?
For example:
template <typename T>
void func(size_t sz, size_t pos)
{
static constexpr std::align_val_t __al = std::align_val_t(alignof(T));
T* data= static_cast<T*>(::operator new(sz * sizeof(T), __al));
data[pos] = T(1, 2); //is this legal? thechnically object at data[pos] is in some undetermenistic state.
}
This is valid only for scalar types (like numeric types or any pointer type), or class types (including unions) that have a "trivial" default constructor, or arrays of such types. If T
is a class type with non-trivial default constructor or no default constructor, or an array of such class types, it is undefined behavior to call any member function on memory where no object was created, even if that member is a copy assignment operator.
(The current C++20 draft has some changes in [basic.life] which appear to also exclude the case of a trivial default constructor, but I'm not entirely sure of the implication.)
The correct and safe way to do this is using "placement new":
template <typename T>
void func(size_t sz, size_t pos)
{
static constexpr std::align_val_t al = std::align_val_t(alignof(T));
std::byte* buffer = static_cast<std::byte*>(::operator new(sz * sizeof(T), al));
T* data = ::new(static_cast<void*>(buffer + pos*sizeof(T))) T(1, 2);
}
The above passes the arguments 1, 2
directly to the constructor of T
which is invoked by the new-expression. If the example was an oversimplification and you did have some other reason to default-initialize the object (assuming default-initialization is possible) and then reassign it, that's simple too:
template <typename T>
void func(size_t sz, size_t pos)
{
static constexpr std::align_val_t __al = std::align_val_t(alignof(T));
std::byte* buffer = static_cast<std::byte*>(::operator new(sz * sizeof(T), al));
T* data = ::new(static_cast<void*>(buffer + pos*sizeof(T))) T(1, 2);
// Whatever other logic...
data[pos] = T(1, 2);
}