5

“placement new”运算符声明如下:

void* operator new (std::size_t size, void* ptr) noexcept;

但是虽然它不涉及任何实际分配,因此消除了错误的分配异常,但指针仍然有可能指向错误的位置,在这种情况下,人们会期望得到范围或上溢/下溢错误,但不会它被声明为noexcept简单地终止执行的事实吗?

这是否也意味着在 C++11 放置之前 new 将抛出并尝试处理std::unexpected以防万一std::set_unexpected而不是直接崩溃?

难道不应该“以防万一”放置新的超载吗?

4

4 回答 4

5

使用布局语法的要点是实现非标准分配,因此通常需要非标准释放。因此采取的行动取决于所使用的分配器。

为新工作的安置提供正确的地址是您的工作。

编辑回应评论: -

#include <new>        // Must #include this to use "placement new"
#include "Fred.h"     // Declaration of class Fred

    void someCode()
    {
      char memory[sizeof(Fred)];     // Line #1     //Allocate enough memory.
      void* place = memory;          // Line #2     // There's no need for this.

      Fred* f = new(place) Fred();   // Line #3 (see "NOTE" below)
      // The pointers f and place will be equal

      ...
    }

注意:您将自行负责传递给“placement new”运算符的指针指向一个足够大的内存区域,并为您正在创建的对象类型正确对齐。编译器和运行时系统都不会尝试检查您是否正确执行此操作。如果您的 Fred 类需要在 4 字节边界上对齐,但您提供的位置没有正确对齐,您可能会遇到严重的灾难。

简而言之,这意味着您应该小心使用placement new,或者如果您像我这样的人那么永远不要使用它:)

希望这可以消除您的疑虑。

于 2014-11-02T12:58:45.537 回答
3

为了理解这个函数的作用,我认为有必要看一下new-expression 的作用:它调用分配函数来获取对象的存储空间,然后在分配函数指示的内存区域中构造该对象(通过返回指向所述内存区域的指针)。

这意味着构造永远不会由分配函数本身执行。分配函数有一个奇怪的名字operator new

可以使用placement-new 语法为分配函数提供附加参数:

new int(5)        // non-placement form
new(1,2,3) int(5) // placement-form

但是,placement-new通常指的是一个非常具体的 new-expression

void* address = ...;
::new(address) int(5) // "the" placement-form

这种形式旨在在已分配的内存区域中构造对象,即它旨在调用构造函数,但不执行任何分配。

该案例的核心语言中没有引入任何特殊案例。相反,标准库中添加了一个特殊的分配函数:

void* operator new (std::size_t size, void* ptr) noexcept;

作为一个无操作(return ptr;),它允许显式调用对象的构造函数,在给定的内存位置进行构造。这个函数调用可以被编译器消除,所以不会引入任何开销。

于 2014-11-02T13:42:12.377 回答
0

您似乎认为该函数可以以某种方式验证它传递的指针。

这不可以。语言标准中没有任何内容允许这样做。当然,检查 nullptr 的情况是可能的,但只有一点点有用。

对齐错误是严格的 UB,因此任何实现都可以自由地做任何事情。(即使只是让它工作:x86)

检查内存区域是否足够大,尤其是对于放置新的位置没有任何意义,因为用户代码很可能也会在该区域中放置其他东西,而编译器无法检查。除此之外,C 和 C++ 还没有提供检查内存分配区域大小的能力。

于 2014-11-02T14:11:06.123 回答
0

存在放置new以使可能的显式构造函数调用针对任意缓冲区(用于自定义分配器、调试等)。就是这样。

您可以编写自己的来验证其输入。

例如:一个类可能需要某种对齐方式,而您怀疑某些自定义分配器会弄虚作假。所以,你给这个类一个不同的新位置,看看当分配器使用它时会发生什么。

于 2014-11-02T12:49:21.177 回答