C++ 将运算符new(sizeof(T)*N)返回的内存作为数组处理

C++ 将运算符new(sizeof(T)*N)返回的内存作为数组处理,c++,arrays,language-lawyer,placement-new,alignas,C++,Arrays,Language Lawyer,Placement New,Alignas,在C语言中,可以使用malloc(sizeof(T)*N)分配动态数组,然后使用指针算法获取动态数组中i偏移处的元素 在C++中,可以使用与 MalCube()/相同的方式使用运算符new()/Cuff>,然后放置新的(例如,可以在Head萨特中的一本书中看到“13个C++:47个工程难题、编程问题和解决方案”的解决方案)。如果您没有,此问题的解决方案总结如下: T* storage = operator new(sizeof(T)*size); // insert element T

在C语言中,可以使用
malloc(sizeof(T)*N)
分配动态数组,然后使用指针算法获取动态数组中i偏移处的元素

<>在C++中,可以使用与<代码> MalCube()/<代码>相同的方式使用<代码>运算符new()/Cuff>,然后放置新的(例如,可以在Head萨特中的一本书中看到“13个C++:47个工程难题、编程问题和解决方案”的解决方案)。如果您没有,此问题的解决方案总结如下:

T* storage = operator new(sizeof(T)*size);

// insert element    
T* p = storage + i;
new (p) T(element);

// get element
T* element = storage[i];
对我来说,这看起来是合法的,因为我要求一块内存,它有足够的内存来容纳大小为
sizeof(T)
的N个对齐元素。由于
sizeof(T)
应该返回对齐的元素的大小,并且它们一个接一个地放置在内存块中,所以在这里使用指针算法是可以的

但是,我指向了链接:“或者”,并声称C++中的代码>运算符NeW()/Case>不返回数组对象,因此指针算法在它返回的东西上使用数组作为一个未定义的行为,而不是ANSI C.

我不擅长这种低级的东西,我真的想通过阅读这个来理解:或者这个:但我还是不明白萨特是否完全错了

我确实理解,
alignas
在以下结构中有意义:

alignas(double) char array[sizeof(double)];
(c)

如果数组似乎不在
double
的边界内(可能在2字节读取处理器上运行的结构中紧跟
char

但这是不同的-我已经从堆/空闲存储请求了内存,特别是请求了操作符new返回内存,它将保存与
sizeof(T)
对齐的元素

总结本例为TL;博士:

    < C++ > 中的动态数组是否可以使用<代码> MARROCK()/<代码>? <> LI>是否可以使用<代码>运算符new()/COD>以及在旧的C++中动态数组的新设置,它没有<代码>对齐方式< /Cord>关键字?< /LI>
  • 指针算术在
    运算符new()返回的内存上使用时是否未定义行为
  • 萨特是不是在建议可能会在古董机器上坏掉的代码

很抱歉,这是愚蠢的。

分配内存上的指针算术问题,如您的示例所示:

T* storage = static_cast<T*>(operator new(sizeof(T)*size));
// ...
T* p = storage + i;  // precondition: 0 <= i < size
new (p) T(element);
T*storage=static_cast(新操作符(sizeof(T)*大小));
// ...
T*p=存储+i;//先决条件:0您可以使用“老式的”
malloc
,它为您提供了一个内存块,在相应的平台上实现了最严格的对齐(例如
长双精度
)。因此,您将能够在不违反任何对齐要求的情况下将任何对象放置到这样的缓冲区中

因此,您可以基于这样的内存块为您的类型的数组使用placement new:

struct MyType {
    MyType() {
        cout << "in constructor of MyType" << endl;
    }
    ~MyType() {
        cout << "in destructor of MyType" << endl;
    }
    int x;
    int y;
};

int main() {

    char* buffer = (char*)malloc(sizeof(MyType)*3);
    MyType *mt = new (buffer)MyType[3];

    for (int i=0; i<3; i++)  {
        mt[i].~MyType();
    }
    free(mt);
}
struct MyType{
MyType(){

cout对于所有广泛使用的最新posix兼容系统,即Windows、Linux(&Android ofc.)和MacOSX,以下内容适用

在C++中,可以使用MalCube()来实现动态数组吗? 是的。使用

reinterpret\u cast
将生成的
void*
转换为所需的指针类型是最佳实践,它产生如下动态分配数组:
type*array=reinterpret\u cast(malloc(sizeof(type)*array\u size);
请注意,在这种情况下,不会对数组元素调用构造函数,因此无论
类型是什么,它仍然是未初始化的存储。当
free
用于释放时,也不会调用析构函数


是否可以在没有C++的关键字的? 是的,但如果使用自定义位置(即不来自malloc/new的位置)为其提供数据,则需要注意放置新位置时的对齐。普通运算符new以及malloc将提供本机字对齐的内存区域(至少在分配大小>=字大小时)。这一事实以及确定结构布局和大小以便正确考虑对齐的事实,如果使用malloc或new,您无需担心dyn阵列的对齐问题。 有人可能会注意到,字大小有时明显小于最大的内置数据类型(通常为

长双精度
),但它必须以相同的方式对齐,因为对齐与数据大小无关,而与不同访问大小的内存总线地址的位宽有关


指针算术在运算符new()返回的内存上使用时是否未定义行为

不,只要您尊重进程的内存边界——从这个角度来看,
new
基本上与
malloc
的工作方式相同,而且,
new
实际上在绝大多数实现中调用malloc以获得所需的区域。 事实上,指针算法本身从来都不是无效的。但是,计算为指针的算术表达式的结果可能指向允许区域之外的位置,但这不是指针算法的错误,而是有缺陷的表达式的错误


萨特是不是在建议可能会在古董机器上坏掉的代码

如果使用了正确的编译器,我不这么认为。(不要将avr指令或128位宽内存mov编译成打算在80386上运行的二进制文件)
当然,在不同内存大小和布局的不同机器上,相同的文字地址可以访问不同用途/状态/存在的区域,但为什么不使用文字地址,除非将驱动代码写入特定硬件?……/P>< P> C++标准包含一个打开的对象的底层表示不是一个“数组”是由
无符号字符
对象组成的“序列”。尽管如此,每个人都将其视为数组(这是预期的)
char* storage = static_cast<char*>(operator new(sizeof(T)*size));
// ...
char* p = storage + sizeof(T)*i;  // precondition: 0 <= i < size
new (p) T(element);