c++ - 为什么std::make_shared无法使用已删除的运算符new编译类型?

标签 c++ memory-management

我正在尝试编写禁止堆的类型,即在堆分配的内存上不可构造的类型。通过删除new运算符和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>();

最佳答案

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


[util.smartptr.shared.create]

2效果:分配适用于T型对象的内存
并通过放置在该内存中构造一个对象
new-expression ::​new (pv) T(std​::​forward<Args>(args)...)。的
模板allocate_­shared使用的副本来分配内存。如果
抛出异常,该功能无效。


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


[expr.new]

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


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

关于c++ - 为什么std::make_shared无法使用已删除的运算符new编译类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59795722/

相关文章:

c++ - 在 QtCreator 中逐行读取文本文件不起作用

c++ - 命令行工具的最佳设计

memory-management - 试图分配已经分配的变量

c# - 使用 LRU 策略的默认内存缓存

Java:引用意味着多少内存?

c++ - 如何确定 map 中是否存在字符串键?

c++ - 期望在 'typename' 之后有一个合格的名字

c - C 中的动态内存释放

c++ - C++ 代码能否与其他 C++ 代码可靠地交互?

randomForest模型大小取决于训练集大小: A way to avoid?