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

问题描述 投票:1回答:2

我正在尝试编写禁止堆的类型,即在分配给堆的内存上不可构造的类型。通过删除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>();
c++ memory-management
2个回答
2
投票

std::make_shared<T>()基本上做到了这一点(为了便于说明,显然将其简化):

template<T>
struct detail {
  int strong_ref_count;
  int weak_ref_count;
  T data;
};

...
return new detail<T>();
...

您可以看到,不是T被“更新”,它是一个复合类型,恰好有T作为成员。

Edit:由于您正在尝试编写禁止堆的类型,因此无论是否应该使用std::make_shared()来进行此操作(请参见下面的评论)都不会改变该特定合成盲点已绑定的事实或早或晚导致您遇到其他问题。


1
投票

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

[util.smartptr.shared.create]

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

分配的内存通常用于控制块,而不直接用于new T。然后通过new放置来构造对象,但是新表达式完全有资格使用全局放置operator new,而不是任何特定于类的放置。这两种用法将完全绕过您自定义删除的运算符。

© www.soinside.com 2019 - 2024. All rights reserved.