Pat*_*oul 4 c++ make-shared c++11
使用std::make_shared<C>该类时,不会调用重载的new / delete运算符。
使用时std::shared_ptr<C>,std::unique_ptr<C>与std::make_unique<C>类超载新/使用delete运算符。
查看文档时,它是完全正确的且有据可查。
cppreference解释了该行为:
std::make_shared使用:: new,因此,如果使用特定于类的运算符new设置了任何特殊行为,则它将不同于std::shared_ptr<T>(new T(args...))。
下面是一些伪代码,可以更好地突出显示行为:
#include <memory>
class C {
public:
void* operator new(size_t size) {
void* p = ::operator new(size);
std::cout << "C::new() -> " << p << "\n";
return p;
}
void operator delete(void* p) {
std::cout << "C::delete() -> " << p << "\n";
::operator delete(p);
}
};
std::shared_ptr<C> ptr = std::make_shared<C>();
Run Code Online (Sandbox Code Playgroud)
从外部的角度来看,它似乎不一致且容易出错。应该始终使用重载类new / delete运算符。
那么,这种行为的原理是什么?
而且,C ++规范在哪里详细说明了std::make_shared行为?
谢谢你的帮助。
那么,行为的合理性是什么?
这样做的原因是因为make_shared不仅分配了对象,还分配了的控制块shared_ptr。为了使其尽可能高效,它调用new一次并一次性为控制块和对象分配足够的存储空间。否则,它将不得不调用new两次,这会使分配开销增加一倍。
如果您想使用自定义分配器,则需要使用std::allocate_shared,它将使用您的自定义分配器进行一次内存获取来创建shared_ptr。
另一种选择是使用std::make_unique来创建unique_ptr,然后使用来初始化shared_ptr。之所以有效,是因为unique_ptr没有控制块,所以std::make_unique以
unique_ptr<T>(new T(std::forward<Args>(args)...))
Run Code Online (Sandbox Code Playgroud)
那会给你
std::shared_ptr<C> ptr = std::make_unique<C>();
Run Code Online (Sandbox Code Playgroud)
哪个输出
C::new() -> 0xf34c20
C::delete() -> 0xf34c20
Run Code Online (Sandbox Code Playgroud)
此行为的直接原因是std::make_shared执行单个分配以同时分配控制块和对象的事实。它没有其他选择,只能为此使用全局运算符new。
另外,我想提到的是,我个人认为对于C ++最不理想的功能之一,可以重载new / delete运算符。类不应规定其内存分配方法。而是,应该将类分配委派给手头的特定任务,并且设计良好的类应该表现得一样好,无论是在动态存储,自动存储,内存映射文件还是闪存卡中进行分配。