为什么 std::make_shared 无法针对已删除运算符 new 的类型进行编译?

nec*_*rek 4 c++ memory-management

我正在尝试编写堆禁止类型,即在堆分配的内存上不可构造的类型。通过删除操作符 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>();
Run Code Online (Sandbox Code Playgroud)

Sto*_*ica 6

std::make_shared是根据 指定的::?new (pv) T(std?::?forward<Args>(args)...)

[util.smartptr.shared.create]

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

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

[expr.new]

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

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