【发布时间】:2018-12-23 17:01:46
【问题描述】:
当前草案标准明确states 表明放置new[] 可以有空间开销:
这种开销可能会应用于所有数组 new 表达式,包括那些引用库函数 operator new[](std::size_t, void*) 和其他布局分配函数的表达式。每次调用 new 时,开销可能会有所不同。
所以大概他们有什么想法,为什么编译器需要这种开销。它是什么?编译器可以将此开销用于任何有用的事情吗?
在我的理解中,要破坏这个数组,唯一的解决方案是在循环中调用析构函数(我是对的吗?),因为没有放置 delete[](顺便说一句,我们不应该有放置 @987654327 @ 正确破坏数组,而不仅仅是它的元素?)。所以编译器不必知道数组长度。
我认为由于这种开销不能用于任何有用的事情,编译器不会使用它(因此这在实践中不是问题)。我用这个简单的代码检查了编译器:
#include <stdio.h>
#include <new>
struct Foo {
~Foo() { }
};
int main() {
char buffer1[1024];
char buffer2[1024];
float *fl = new(buffer1) float[3];
Foo *foo = new(buffer2) Foo[3];
printf("overhead for float[]: %d\n", (int)(reinterpret_cast<char*>(fl) - buffer1));
printf("overhead for Foo[] : %d\n", (int)(reinterpret_cast<char*>(foo) - buffer2));
}
GCC 和 clang 根本不使用任何开销。但是,对于 Foo 情况,MSVC 使用 8 个字节。 MSVC 可以出于什么目的使用此开销?
这里有一些背景,我为什么提出这个问题。
之前有关于这个主题的问题:
- Array placement-new requires unspecified overhead in the buffer?
- Can placement new for arrays be used in a portable way?
据我所知,这些问题的寓意是避免使用布置new[],并在循环中使用布置new。但是这个解决方案不会创建一个数组,但是使用operator[] 的元素彼此相邻,这不是一个数组,对它们来说是未定义的行为。这些问题更多是关于如何避免放置new[],但这个问题更多是关于“为什么?”。
【问题讨论】:
-
小心从这个简单的测试中解释“行为差异”。我将您的代码粘贴到 Godbolt 中,发现 gcc 已经意识到对
placement new[]的调用是完全多余的,并且已将其删除! godbolt.org/g/94Deyp -
@RichardHodges:嗯,为什么它在这里相关?
-
还要注意 gcc 能够“看到” Foo 的析构函数是空操作。我当然希望它能够利用规则来支持高效的代码。
-
关键是在这种情况下,编译器看到不需要存储一个幻数来告诉它数组有多长——因为它不需要在调用 delete 时调用 N 个析构函数[]。 gcc 充分利用其对 float 和 Foo 类型的了解,以优化这两个分配数组的内存存储和行为。
-
@RichardHodges: 一样,0 开销。
标签: c++