C++单例静态函数调用std::make_shared无法访问私有构造函数问题
错误原因
你遇到的编译报错本质是权限访问上下文的问题:
类的静态成员函数确实有权限调用私有构造函数,但std::make_shared<T>是标准库提供的全局模板函数,构造对象的实际操作是在std::make_shared的内部逻辑中执行的,该函数不属于GLFWContextSingleton的成员也没有被声明为友元,因此没有权限访问类的私有构造函数,和你在哪个函数里调用std::make_shared无关。
修复方案
不推荐声明std::make_shared为友元的方式,该方式强依赖标准库的内部实现,可移植性差,常用的可行修复方案有两种:
- 方案1:直接用new构造对象(改动最小)
放弃使用std::make_shared,直接在GetInstance函数内调用new创建对象,此时构造函数的调用上下文是类的静态成员函数,有权限访问私有构造,修改后的GetInstance代码如下:
std::shared_ptr<GLFWContextSingleton> GLFWContextSingleton::GetInstance() { static std::weak_ptr<GLFWContextSingleton> weak_singleton_instance; auto singleton_instance = weak_singleton_instance.lock(); if (singleton_instance == nullptr) { // 直接在当前上下文调用私有构造,权限合法 singleton_instance = std::shared_ptr<GLFWContextSingleton>(new GLFWContextSingleton()); weak_singleton_instance = singleton_instance; } return singleton_instance; }
- 方案2:密钥模式保留std::make_shared的优化特性
std::make_shared会把对象和控制块分配在同一块内存,性能更优,如果要保留这个特性,可以用密钥访问的方式实现:
首先修改类的声明,增加私有密钥类型,修改构造函数的公开签名:
#ifndef GLFW_CONTEXT_H #define GLFW_CONTEXT_H #include <memory> class GLFWContextSingleton { public: static std::shared_ptr<GLFWContextSingleton> GetInstance(); ~GLFWContextSingleton(); GLFWContextSingleton(const GLFWContextSingleton& other) = delete; GLFWContextSingleton* operator=(const GLFWContextSingleton* other) = delete; // 构造函数公开,但需要传入私有类型的密钥,外部无法调用 GLFWContextSingleton(struct ConstructorToken) {} private: // 私有密钥类型,只有类内部可以访问 struct ConstructorToken {}; }; #endif
然后修改GetInstance的实现,传入密钥调用std::make_shared:
std::shared_ptr<GLFWContextSingleton> GLFWContextSingleton::GetInstance() { static std::weak_ptr<GLFWContextSingleton> weak_singleton_instance; auto singleton_instance = weak_singleton_instance.lock(); if (singleton_instance == nullptr) { // 类内部可以访问ConstructorToken类型,构造合法 singleton_instance = std::make_shared<GLFWContextSingleton>(ConstructorToken{}); weak_singleton_instance = singleton_instance; } return singleton_instance; }
内容的提问来源于stack exchange,提问作者nick2225
相关产品推荐
相关产品推荐

