0

基于这个问题:可变大小类型分配

下面的工作吗?

{
    // size calculated.
    std::auto_ptr<Base> p(new((void*)(new char[size])) Packet());

    // Do Stuff
}

Packet 是 POD 结构,其中最后一个成员是数组。这个想法是允许一个动态大小的数组(就像我们多年前在 C 中所做的那样)

struct Packet
{
    // STUFF
    int  data[1];
}
4

2 回答 2

2

不,这不起作用:使用任何形式的new额外参数构造的对象,除了std::nothrow需要显式销毁并单独处理内存:

void* memory = operator new(size);
T* ptr = new(memory) T(args);
...
ptr->~T();
operator delete(memory);

另请注意,分配原始内存的方式不是这样的new char[size]:这会在内存中构造char需要销毁的对象。我意识到构造和破坏实际上都没有对内置类型做任何事情,但我很高兴实现可以做某事,据我所知,没有权限跳过这些析构函数。

最后,请注意,您还需要构造int对象,并且允许在结构的明显结束之后放置一些内容。

于 2012-03-15T07:04:25.193 回答
1

如果我错过了问题中隐含的一个重要点,我很抱歉,我没有看到它。但是,关于这条中心线:

std::auto_ptr<Base> p(new((void*)(new char[size])) Packet());

这是我认为可以说的:

  1. 最后的构造函数调用应该是Packet, not Packet(),尽管实际上编译器可能会按原样接受它,并且可能没有任何区别

  2. 内部分配new char[size]使用数组分配器new []CPP 参考说明了表达式new [array_n]

请注意,由于编译器编码的附加信息(例如数组的大小,因为需要此信息才能正确销毁数组中的对象),因此可能会分配超过 size_of( type ) * array_n 。

现在,外部分配器调用是placement newnew ((void*)(...))的一个实例,这里描述如下:

void* operator new ( std::size_t, void* ptr ); 什么都不做,返回 ptr。

换句话说,调用可能会new []导致编译器分配比数组严格要求更多的内存,并在额外空间中编码与大小相关的信息。然而,由于placement new“什么都不做”,它不会以任何方式处理或删除额外的信息。

但是,由于使用std::auto_ptr意味着将使用(而不是)执行释放,因此无法正确释放额外信息,因此可能导致内存泄漏或更糟。delete delete []

编辑:为避免仅依赖 CPP 参考,C++ 标准 N3337的相关部分如下:

  • § 18.6.1.2 规定,仅delete应用于释放分配的空间new,并相应地delete []用于分配的空间new []
  • § 18.6.1.3 明确指出,放置形式newnew []执行任何操作。这意味着两者都不能用于将单个对象空间“转换”为数组空间。

现在也许真正的问题delete []是,如果仅用于稍后释放空间,则问题中提出的放置新的应用是否有效。也许答案是未定义的(应该被解释为等同于“否”)。

于 2012-03-15T14:37:09.863 回答