1

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

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

#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 进行构建。

4

3 回答 3

10

§5.3.4/12:

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

[ ... ]

这里,x 和 y 是表示数组分配开销的非负未指定值;new-expression 的结果将从 operator new[] 返回的值偏移这个量。这种开销可以应用于所有数组 new 表达式,包括那些引用库函数 operator new[](std::size_t, void*) 和其他布局分配函数的表达式。开销的数量可能因一次调用 new 到另一次而异。[强调补充]

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

于 2011-04-19T20:05:16.857 回答
1

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

5.3.4:

new-expression将请求的空间量作为 type 的第一个参数传递给分配函数 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;
}

但我从来没有试过这个。

于 2011-04-19T19:45:32.787 回答
0

当您使用时,operator new[]您必须使用operator delete[]. 您不能new[]一一分配然后解除分配。因此,您可以这样做,而不是您的释放循环:

delete [] pp;
于 2011-04-20T14:46:45.903 回答