安置新的奇怪行为

时间:2011-04-19 19:21:08

标签: c++ placement-new

不要问我想要做什么,这只是一个快速测试,其唯一目的是查看新位置是否有问题。

我发现了一个问题,或者我只是误解了一些问题。

#include <vector>

using namespace std;

#define WORKS 
int main(int argc, char** argv) {
    vector<int>* pp = (vector<int>*)malloc(sizeof(vector<int>)*20);

#ifdef WORKS
    for(int i = 0; i < 20; ++i)
    new (pp+i) vector<int>;
#else
    new (pp) vector<int>[20];
#endif

    for(int i = 0; i < 20; ++i) 
        pp[i].~vector<int>();

}

当您删除“#define WORKS”时,它会为您提供访问冲突,例如

    for(int i = 0; i < 20; ++i)
    new (pp+i) vector<int>;

效果不错,与

不同
    new (pp) vector<int>[20];

这是在销毁阶段抛出异常的原因。这里发生了什么? 我正在使用Windows XP并使用VC ++ Express 2010进行构建。

3 个答案:

答案 0 :(得分:10)

§5.3.4/ 12:

  

- new T[5]会调用operator new[](sizeof(T)*5+x)

     

[...]

     

这里,x和y是表示数组分配开销的非负未指定值; new-expression的结果将由operator new []返回的值抵消。此开销可以应用于所有数组新表达式,包括引用库函数operator new [](std :: size_t,void *)和其他放置分配函数。开销的数量可能因新的一次调用而异。 [强调补充]

总而言之,尝试放置数组可能需要一些未分配的未指定数量的开销。只要您单独放置元素,就不允许这样的开销,因此放置新元素。

答案 1 :(得分:1)

新表达式的结果不必位于传递给placement new运算符的同一地址。而且,您无法保证分配数组所需的大小严格来说是单个元素的大小乘以元素数量。

5.3.4:

  

new-expression 传递金额   要求分配的空间   作为类型的第一个参数   std::size_t。那个论点应该是   不小于对象的大小   被创造; 可能更大   而不是物体的大小   仅当对象是一个时才创建   阵列

因此,您的代码版本将更正确:

     void *ppstorage= malloc(sizeof(vector<int>)*20);
    pp= new (ppstorage) vector<int>[20];

    for(int i = 0; i < 20; ++i) 
        pp[i].~vector<int>();

虽然你几乎可以肯定地写出ppstorage的结尾。编译器必须在某处存储数组的计数以正确地破坏每个元素,并且存储在新表达式返回的地址之前存储的MSVC。

理论上,您可以重载operator new[]以获取数组的实际分配大小:

void *operator new[](size_t *allocation_size, size_t size)
{
    *allocation_size= size;
    return nullptr;
}

但我从未尝试过这个。

答案 2 :(得分:0)

使用operator new[]时,必须使用operator delete[]取消分配。您无法使用new[]进行分配,然后逐个解除分配。所以不是你的释放循环,你会这样做:

delete [] pp;