为何make_shared无法构造对象?shared_ptr(new)却可行?
咱们来一步步拆解这两种写法的本质差异,就能明白问题出在哪了:
1. std::shared_ptr(new Foo(i))能正常工作的原因
你的getFoo是Foo类的成员函数,类的成员函数天然拥有访问**protected/private成员(包括构造函数)**的权限。所以在getFoo里直接执行new Foo(i)是完全合法的——对象已经被成功创建出来了,std::shared_ptr在这里只是接管这个已经存在的裸指针,负责后续的引用计数和内存释放。它根本不需要去调用Foo的构造函数,自然不会触发权限检查。
2. std::make_shared编译失败的核心原因
std::make_shared的工作逻辑和上面完全不同:它会在函数内部一次性分配内存(对象内存+引用计数内存),然后直接调用对象的构造函数来创建实例。但问题在于,std::make_shared是标准库提供的全局函数,它既不是Foo类的成员,也没有被声明为Foo的友元,所以它没有权限访问Foo的protected构造函数。
标准库为了提前发现这种权限问题,特意在make_shared里加了static_assert断言,检查is_constructible<Foo, int&>::value(简单说就是检查外部能不能用int参数构造Foo)。因为构造函数是protected的,外部函数无法调用,所以这个断言直接失败,就报出了你看到的错误:Static_assert failed due to requirement 'is_constructible<Foo, int &>::value' "Can't construct object in make_shared"。
关于“构造函数设为私有可规避问题”的补充
其实不管构造函数是protected还是private,std::shared_ptr(new Foo(i))都能正常工作——因为成员函数依然有权限调用私有构造函数;而std::make_shared依然会失败,因为它还是没有权限访问私有构造。你说的“规避”应该是指用shared_ptr(new...)的方式依然可行,而非make_shared能工作。
总的来说,两者的核心差异就是谁在调用构造函数:shared_ptr(new...)是你在有权限的成员函数里调用,而make_shared是无权限的标准库函数调用,这就是导致结果不同的根本原因。
内容的提问来源于stack exchange,提问作者user9833551

