将运算符new(sizeof(T)* N)返回的内存视为数组 [英] treating memory returned by operator new(sizeof(T) * N) as an array

查看:180
本文介绍了将运算符new(sizeof(T)* N)返回的内存视为数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In C one can allocate dynamic arrays using malloc(sizeof(T) * N) and then use pointer arithmetic to get elements at i offset in this dynamic array.

在C ++中,可以使用operator new()malloc()相同的方式进行类似操作,然后放置新的内容(例如,可以在"Exceptional C ++:47个工程难题,编程问题,和解决方案".如果您没有,则此问题的解决方案摘要为:

In C++ one can do similar using operator new() in the same way as malloc() and then placement new (for an example one can see solution for item 13 in a book "Exceptional C++: 47 engineering puzzles, programming problems, and solutions" by Herb Sutter). If you don't have one, the summary of the solution for this question would be:

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)应该返回对齐后的元素的大小,并且将它们一个接一个地放置在一块内存中,因此可以使用指针算法.

For me this looked legit since I'm asking for a chunk of memory with enough memory to hold N aligned elements of size = sizeof(T). Since sizeof(T) should return a size of element which is aligned, and they are laid one after another in a chunk of memory, using pointer arithmetic is OK here.

但是,后来我却指向诸如以下的链接: http://eel.is /c++draft/expr.add#4 http ://eel.is/c++draft/intro.object#def:object 并声称在C ++中operator new()不会返回数组对象,因此对返回的对象进行指针算术并将其用作与ANSI C相反,数组是未定义的行为.

However I was then pointed to links like: http://eel.is/c++draft/expr.add#4 or http://eel.is/c++draft/intro.object#def:object and claiming that in C++ operator new() does not return an array object, so pointer arithmetic over what it has returned and using it as an array is undefined behavior as opposed to ANSI C.

我不太擅长使用这些低级的东西,我真的想通过阅读以下内容来理解: https://www.ibm.com/developerworks/library/pa-dalign/或这样:

I'm not this good at such low level stuff and I'm really trying to understand by reading this: https://www.ibm.com/developerworks/library/pa-dalign/ or this: http://jrruethe.github.io/blog/2015/08/23/placement-new/ but I still fail to understand if Sutter was just plain wrong?

我确实理解alignas在诸如以下的构造中是有意义的:

I do understand that alignas make sense in constructions such as:

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

(c) http://georgeflanagin.com/alignas.php

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

If array appears to be not in a boundary of double (perhaps following char in a structure ran at 2-byte reading processor).

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

But this is different - I've requested memory from the heap/free storage especially requested operator new to return memory which will hold elements aligned to sizeof(T).

总结一下,如果这是TL; DR:

To summarize in case this was TL;DR:

  • 是否可以将malloc()用于C ++中的动态数组?
  • 是否可以在没有alignas关键字的旧C ++中对动态数组使用operator new()并放置新内容?
  • operator new()返回的内存上使用时,指针算术是否为未定义行为?
  • 萨特(Sutter)是否建议某些古董机器可能会破解的代码?
  • Is it possible to use malloc() for dynamic arrays in C++?
  • Is it possible to use operator new() and placement new for dynamic arrays in older C++ which has no alignas keyword?
  • Is pointer arithmetic undefined behavior when used over memory returned by operator new()?
  • Is Sutter advising code which might break on some antique machine?

对不起,这很愚蠢.

推荐答案

C ++标准包含一个开放的

The C++ standards contain an open issue that underlying representation of objects is not an "array" but a "sequence" of unsigned char objects. Still, everyone treats it as an array (which is intended), so it is safe to write the code like:

char* storage = static_cast<char*>(operator new(sizeof(T)*size));
// ...
char* p = storage + sizeof(T)*i;  // precondition: 0 <= i < size
new (p) T(element);

只要void* operator new(size_t)返回正确对齐的值即可.使用sizeof乘以偏移量来保持对齐是安全.

as long as void* operator new(size_t) returns a properly aligned value. Using sizeof-multiplied offsets to keep the alignment is safe.

在C ++ 17中,有一个宏> STDCPP_DEFAULT_NEW_ALIGNMENT ,用于指定正常" void* operator new(size_t)的最大安全对齐方式;如果需要更大的对齐方式,则应使用void* operator new(std::size_t size, std::align_val_t alignment).

In C++17, there is a macro STDCPP_DEFAULT_NEW_ALIGNMENT, which specifies the maximum safe alignment for "normal" void* operator new(size_t), and void* operator new(std::size_t size, std::align_val_t alignment) should be used if a larger alignment is required.

在早期版本的C ++中,没有这种区别,这意味着void* operator new(size_t)需要以与任何对象的对齐方式兼容的方式来实现.

In earlier versions of C++, there is no such distinction, which means that void* operator new(size_t) needs to be implemented in a way that is compatible with the alignment of any object.

关于能够直接在T*上执行指针算术,我不确定需要是标准所必需的.但是,很难以无法使用的方式来实现C ++内存模型.

As to being able to do pointer arithmetic directly on T*, I am not sure it needs to be required by the standard. However, it is hard to implement the C++ memory model in such a way that it would not work.

这篇关于将运算符new(sizeof(T)* N)返回的内存视为数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆