如何阻止通过默认初始化或new关键字创建FibonacciMemoization实例
要实现仅通过FibonacciMemoization::getInstance()创建实例的单例,必须把类的构造、析构、拷贝构造、赋值运算符设为私有或删除,阻止外部直接new或栈上创建对象。但std::make_shared需要访问这些私有成员,导致编译错误,以下是几种可行的解决方法:
方案1:声明std::make_shared和std::default_delete为友元
通过友元授权,让std::make_shared能调用私有构造函数,std::default_delete能调用私有析构函数,同时保留make_shared内存分配连续的优势。
#include <memory> class FibonacciMemoization { private: // 私有构造、析构,禁止拷贝和赋值 FibonacciMemoization() = default; ~FibonacciMemoization() = default; FibonacciMemoization(const FibonacciMemoization&) = delete; FibonacciMemoization& operator=(const FibonacciMemoization&) = delete; // 授权std::make_shared访问私有构造 template<typename T, typename... Args> friend std::shared_ptr<T> std::make_shared(Args&&... args); // 授权std::default_delete访问私有析构 template<typename T> friend struct std::default_delete; static std::shared_ptr<FibonacciMemoization> instance; public: static std::shared_ptr<FibonacciMemoization> getInstance() { if (!instance) { instance = std::make_shared<FibonacciMemoization>(); } return instance; } // 示例记忆化斐波那契计算函数 int calculate(int n) { static std::vector<int> memo; if (n < memo.size()) return memo[n]; if (n <= 1) { memo.resize(n+1); memo[n] = n; return n; } int res = calculate(n-1) + calculate(n-2); memo.push_back(res); return res; } }; // 初始化静态实例指针 std::shared_ptr<FibonacciMemoization> FibonacciMemoization::instance = nullptr;
方案2:直接用new构造shared_ptr
放弃make_shared的内存效率,直接在getInstance中用new创建对象,再传入shared_ptr构造函数。这种方式代码更简单,无需友元声明。
#include <memory> class FibonacciMemoization { private: FibonacciMemoization() = default; ~FibonacciMemoization() = default; FibonacciMemoization(const FibonacciMemoization&) = delete; FibonacciMemoization& operator=(const FibonacciMemoization&) = delete; static std::shared_ptr<FibonacciMemoization> instance; public: static std::shared_ptr<FibonacciMemoization> getInstance() { if (!instance) { instance = std::shared_ptr<FibonacciMemoization>(new FibonacciMemoization()); } return instance; } // 示例成员函数 int calculate(int n) { // 斐波那契计算逻辑 if (n <= 1) return n; return calculate(n-1) + calculate(n-2); } }; std::shared_ptr<FibonacciMemoization> FibonacciMemoization::instance = nullptr;
方案3:用内部辅助类封装创建逻辑
通过私有内部类Helper来访问构造和析构,避免使用友元,保持类的封装性。
#include <memory> class FibonacciMemoization { private: FibonacciMemoization() = default; ~FibonacciMemoization() = default; FibonacciMemoization(const FibonacciMemoization&) = delete; FibonacciMemoization& operator=(const FibonacciMemoization&) = delete; // 内部辅助类,负责创建和销毁实例 struct Helper { static FibonacciMemoization* create() { return new FibonacciMemoization(); } static void destroy(FibonacciMemoization* ptr) { delete ptr; } }; static std::shared_ptr<FibonacciMemoization> instance; public: static std::shared_ptr<FibonacciMemoization> getInstance() { if (!instance) { instance = std::shared_ptr<FibonacciMemoization>( Helper::create(), Helper::destroy ); } return instance; } // 示例成员函数 int calculate(int n) { // 斐波那契计算逻辑 if (n <= 1) return n; return calculate(n-1) + calculate(n-2); } }; std::shared_ptr<FibonacciMemoization> FibonacciMemoization::instance = nullptr;
以上三种方案都能实现需求:阻止外部直接创建实例,同时让getInstance正常返回std::shared_ptr类型的单例对象,编译运行无报错。
内容的提问来源于stack exchange,提问作者Jason Rich Darmawan
相关产品推荐
相关产品推荐

