C++ 从新分配的内存中分配到对象

C++ 从新分配的内存中分配到对象,c++,object,assignment-operator,C++,Object,Assignment Operator,为数组分配行内存,然后对该数组中的对象调用赋值运算符,这符合标准吗 例如: 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

为数组分配行内存,然后对该数组中的对象调用赋值运算符,这符合标准吗

例如:

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.
}
模板
无效函数(大小和位置)
{
静态constexpr std::align_val_t_ual=std::align_val_t(alignof(t));
T*data=static_cast(::运算符new(sz*sizeof(T),u al));
data[pos]=T(1,2);//这合法吗?data[pos]处的技术对象处于某种未检测状态。
}

不,它无效<代码>数据[pos]不仅仅处于某种不确定状态。在
数据所指向的内存中根本不存在
T
对象。因此,对不存在的对象调用
T::operator=
是无效的

在这种情况下,您需要使用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));
    T* data = static_cast<T*>(::operator new(sz * sizeof(T), __al));
    T* ptr = new (data + pos) T(1, 2);
}
模板
无效函数(大小和位置)
{
静态constexpr std::align_val_t_ual=std::align_val_t(alignof(t));
T*data=static_cast(::运算符new(sz*sizeof(T),u al));
T*ptr=新(数据+位置)T(1,2);
}

这将在内存地址
data+pos
处构造一个新的
T
对象。在释放分配的内存之前,您需要手动调用
T
的析构函数来销毁该对象。

这仅对标量类型(如数值类型或任何指针类型)或具有数组的类类型(包括联合)有效。如果
T
是具有非平凡默认构造函数或无默认构造函数的类类型,或此类类类型的数组,则调用内存中未创建对象的任何成员函数是未定义的行为,即使该成员是复制赋值运算符也是如此

(当前的C++20草案有一些变化,其中似乎也排除了普通默认构造函数的情况,但我不能完全确定其含义。)

正确且安全的方法是使用“placement new”:


不要使用以两个下划线开头的标识符。那些是为C++实现保留的。@ ascPoop-这只是规则中包含两个连续下划线的名字的特例。@ ReMyLeBeAube是从一个下划线开始的标识符,然后是大写字母,或者包含两个连续下划线。@ AsChisher你是对的,我误解了所说的。
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);
}
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);
}