阅读:
接受的答案建议采取new T[n]
如下措施(忽略对齐和 n = 0 的情况):
- 如果
n
= 1 或 T 是可平凡破坏的:
- 分配
sizeof(T)
字节 T
在分配的内存上调用 ctor (如 placement-new)
- 分配
- 如果
n
> 1:
- 分配
sizeof(size_t + n * sizeof(T))
字节 - 将第一个 size_t 字节设置为值
n
T
在每个以下 n 个字节序列上调用 ctorsizeof(T)
(类似于在循环中放置 new)
- 分配
我可以依赖这个吗?也就是说,如果我new T[n]
按照上面的方法在自己的代码中模拟,然后将结果传递给delete[]
– 这会是明确定义且安全的吗?
相关问题:
13
最佳答案
2
我可以依赖这个吗?也就是说,如果我按照上面的方法在自己的代码中模拟新的 T[n],然后将结果传递给 delete[] – 这样是否定义明确且安全?
不,这一切都未指定。您唯一可以确定的是,new T[n]
将使用operator new[]
至少与一样大的大小参数调用n*sizeof(T)
,并将返回一个指针,该T[n]
指针有足够的空间容纳对象,并且已适当对齐。(在的T
情况下,或者有额外的对齐保证。)其他一切都是未指定的实现细节。T
unsigned char
char
std::byte
如果您愿意依赖特定的 ABI 保证,那么您可能会取得更大的成功,尽管从技术上讲,按照标准仍然是 UB。例如,在 Itanium ABI 中,请参见,了解何时以及如何使用数组 cookie。该过程并不像您建议的那样。特别是,如果没有非平凡的析构函数,并且通常的数组释放函数不接受两个参数,则没有 cookie T
。此外,还应用了一个纠正对齐的过程,并且没有特殊的长度情况1
。
3
-
1. 调整了关于可轻易破坏类型的问题。2. 我确实说过“忽略对齐”。不过,我会阅读 Itanium ABI 的相关内容。我可以使用一些预处理器定义来检查 Itanium ABI 吗?
–
-
@einpoklum 我认为没有任何预处理器定义。这是构建系统通常必须知道的事情,因为您必须知道 ABI 才能与其他库链接。
– -
1@einpoklum 注意,可轻易破坏并不是完全条件。在某些情况下(当通常的数组释放函数需要两个参数时),无论如何都必须存储大小。
–
|
作为一般原则,避免对实现的工作方式做出假设。如果您绝对需要这样做,而您又没有实现的详细规范,那么您就是在冒险。即使您有规范,您也会使您的代码不可移植(这在以后可能会很重要,而且总是不受欢迎的),并且仍然有以后实施变更的风险。
在 hand 的情况下,永远不要传递给delete []
您未从 new []’ 收到的内容,而是将其传递给delete []
exact once。
几乎肯定行不通的是分配一个大数组(比如说)并将其部分传递给delete [] 。可能行得通的方法是使用malloc()或低级 O/S 调用(在标准库之外)进行分配并将其传递给delete [](但不保证也不推荐)。
您可能想要实现一个,或者需要分配原始char
内存(使用new []
或malloc()
或其他方式),并使用放置new
来在其中构造对象,并在您想要处置(或回收)它时直接调用析构函数,最终根据您获取它的方式释放该“原始”内存。您甚至可以玩游戏在堆栈上分配内存并允许return
恢复它。
过早优化是万恶之源,像这样调整内存管理并不是首要任务。但如果您的算法正在分配和释放大量对象,那么它可能很有用。
需要特别注意的是,通过充分利用交换和移动语义,可以避免内存流失(大量new
和delete
)。它们和复制省略几乎是为了删除多余的“新建”/复制/“删除”序列而发明的,并且可以带来比优化分配更好的巨大改进。
您要做的事情可能合理。但是您尝试做的方式并不推荐,并且有更安全、更便携的方式来做这件事。
脚注:按照 OP 的要求,我在此答案中忽略了零长度数组和对齐,但是如果您去那里,它们都与自定义分配逻辑相关。
|
new T[1]
并且new T[N]
会做同样的事情(存储元素的数量[通常就在数组元素之前]),因为delete[]
在两种情况下都需要做相同的工作。–
–
new T[N]
分配主要sizeof(T) * N + unspecified_y
用于unspecifed_y
存储N
释放(对于琐碎的可能被省略T
。因此“模拟”需要准确地知道您当前的编译器在做什么(这可能会在版本之间发生变化)。–
~T
(大致就是这样std::vector
)–
malloc
/free
,一个用于new
/delete
,一个用于new[]
/delete[]
。它是一个堆管理器,专注于安全,而不是性能,并且可以检测一些常见问题,例如某些内存写入超限或不足,或者在一个区域外分配并尝试在另一个区域释放。–
|