如何为数组分配行内存,然后对该数组中的对象调用赋值运算符?
例如:
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.
}
答案 0 :(得分:2)
这仅对标量类型(例如数字类型或任何指针类型)或具有"trivial" default constructor的类类型(包括并集)或此类类型的数组有效。如果T
是具有非平凡的默认构造函数或没有默认构造函数的类类型,或此类类的数组,则在未创建对象的内存上调用任何成员函数(即使该成员函数)是未定义的行为是副本分配运算符。
(当前的C ++ 20草案在[basic.life]中进行了一些更改,这些更改似乎也排除了琐碎的默认构造函数的情况,但我并不完全确定其含义。)
正确,安全的方法是使用“新放置”:
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);
}
以上内容将参数1, 2
直接传递给T
的构造函数,该构造函数由new-expression调用。如果该示例过于简化,并且您确实还有其他原因需要默认初始化该对象(假设可以进行默认初始化),然后重新分配它,那也很简单:
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);
}
答案 1 :(得分:0)
否,它无效。 data[pos]
不仅处于不确定的状态。 T
指向的内存中根本没有data
对象。因此,在不存在的对象上调用T::operator=
是无效的。
在这种情况下,您需要使用展示位置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));
T* data = static_cast<T*>(::operator new(sz * sizeof(T), __al));
T* ptr = new (data + pos) T(1, 2);
}
这将在内存地址T
处构造一个新的data + pos
对象。在释放分配的内存之前,您将需要手动调用T
的析构函数来销毁该对象。