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

查看:48
本文介绍了将 operator 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() 相同的方式执行类似操作,然后放置 new(例如,可以查看 item 的解决方案13 在 Herb Sutter 所著的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#4http://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/ 或此:http://jrruethe.github.io/blog/2015/08/23/placement-new/ 但我还是不明白萨特完全错了?

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).

但这是不同的 - 我已经从堆/空闲存储中请求内存,特别是请求 operator 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() 和placement 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?

对不起,如果这是愚蠢的.

Sorry if this is dumb.

推荐答案

C++ 标准包含一个开放的 问题 对象的底层表示不是数组",而是 unsigned char 对象的序列".尽管如此,每个人都将其视为一个数组(这是有意的),因此编写如下代码是安全的:

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-multiplied offsets 来保持对齐是 安全.

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 对齐),如果需要更大的对齐,应该使用.

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.

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

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