【问题标题】:Why doesn't std::make_shared fail to compile for type with deleted operator new?为什么 std::make_shared 不能为已删除运算符 new 的类型编译失败?
【发布时间】:2020-01-17 22:39:11
【问题描述】:

我正在尝试编写堆禁止类型,即在堆分配的内存上不可构造的类型。通过删除 operator new 和placement new 我想我可以做到这一点。但是使用std::make_shared 创建共享指针仍然可以编译。

为什么std::make_shared<A>()删除新的操作符后编译失败?

#include <memory>

class A {
public:
    void* operator new(size_t) = delete;
    void* operator new(size_t, void*) = delete;
    void* operator new [] (size_t) = delete;
};

// Regular new fails
A* a1 = new A();

// Placement new fails
void* pv = std::malloc(sizeof(A));
A* a2 = new (pv) A();

// make_shared works
std::shared_ptr<A> a3 = std::make_shared<A>();

【问题讨论】:

    标签: c++ memory-management


    【解决方案1】:

    std::make_shared::​new (pv) T(std​::​forward&lt;Args&gt;(args)...) 的形式指定。

    [util.smartptr.shared.create]

    2 效果:分配适合 T 类型对象的内存 并通过放置在该内存中构造一个对象 新表达式::​new (pv) T(std​::​forward&lt;Args&gt;(args)...)。这 模板 allocate_shared 使用 a 的副本来分配内存。如果 抛出异常,函数无效。

    分配的内存通常用于控制块,而不是直接用于new T。然后通过placement new 构造对象,但new 表达式完全可以使用全局布局operator new,而不是任何特定于类的布局。

    [expr.new]

    9 如果 new-expression 以一元 ​:: 运算符开头,则 在全局范围内查找分配函数的名称。 否则,如果分配的类型是类类型 T 或其数组, 在 T 的范围内查找分配函数的名称。如果这个 查找找不到名称,或者分配的类型不是类 类型,分配函数的名称在全局范围内查找。

    这两种用途将完全绕过您自定义的删除运算符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-07
      • 2021-10-08
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多