如何禁止向自定义observer_ptr构造函数传入new T?
如何禁止observer_ptr直接接收new T的结果
要禁止observer_ptr<T> var_name(new T);这类违背设计初衷的用法,核心是通过构造函数的重载和删除,阻止右值原始指针(比如new T的返回值)被传入构造函数。下面是具体实现思路和代码示例:
核心思路
new T返回的是右值类型的原始指针(T*&&),我们可以通过两种方式限制:
- 删除接受右值原始指针的构造函数,同时保留接受左值原始指针的版本——强制用户先将原始指针存入左值变量,明确所有权归属自己;
- 仅提供从智能指针(
std::unique_ptr/std::shared_ptr)构造的接口,彻底杜绝直接传入原始指针的可能(适合完全不想处理原始指针的场景)。
实现示例
方案1:限制右值原始指针,允许左值和智能指针构造
#include <memory> template <typename T> class observer_ptr { public: // 允许从左值原始指针构造(用户需自行管理该指针的生命周期) explicit observer_ptr(T*& ptr) : m_ptr(ptr) {} // 允许从智能指针构造(明确所有权由智能指针持有) explicit observer_ptr(const std::unique_ptr<T>& smart_ptr) : m_ptr(smart_ptr.get()) {} explicit observer_ptr(const std::shared_ptr<T>& smart_ptr) : m_ptr(smart_ptr.get()) {} // 支持空指针 observer_ptr(std::nullptr_t) noexcept : m_ptr(nullptr) {} // 禁止从右值原始指针构造(直接传入new T会触发编译错误) observer_ptr(T*&&) = delete; // 必要的成员函数 T& operator*() const { return *m_ptr; } T* operator->() const { return m_ptr; } T* get() const { return m_ptr; } private: T* m_ptr; };
这样编写后,以下用法会编译失败:
// 错误:尝试将右值指针传入已删除的构造函数 observer_ptr<int> p(new int(42));
而合法的用法包括:
// 合法:先将原始指针存入左值,用户自行管理所有权 int* raw = new int(42); observer_ptr<int> p(raw); // 合法:从unique_ptr构造,所有权由unique_ptr持有 auto uptr = std::make_unique<int>(42); observer_ptr<int> p2(uptr); // 合法:空指针 observer_ptr<int> p3(nullptr);
方案2:仅允许从智能指针构造
如果完全不想处理原始指针,可以只保留智能指针的构造函数,删除所有原始指针相关的构造函数:
template <typename T> class observer_ptr { public: explicit observer_ptr(const std::unique_ptr<T>& smart_ptr) : m_ptr(smart_ptr.get()) {} explicit observer_ptr(const std::shared_ptr<T>& smart_ptr) : m_ptr(smart_ptr.get()) {} observer_ptr(std::nullptr_t) noexcept : m_ptr(nullptr) {} // 删除所有原始指针相关的构造函数 observer_ptr(T*) = delete; observer_ptr(T*&) = delete; observer_ptr(T*&&) = delete; // 成员函数同方案1... private: T* m_ptr; };
这种方案下,用户只能从智能指针或空指针创建observer_ptr,彻底避免了手动管理原始指针的风险。
原理说明
C++中,new T的结果是一个临时的右值指针,无法绑定到非const的左值引用(T*&),同时我们显式删除了接受T*&&的构造函数,因此编译器会直接拒绝observer_ptr<T>(new T)这类调用,从语法层面阻止了违背设计初衷的用法。
内容的提问来源于stack exchange,提问作者aallfik11
相关产品推荐
相关产品推荐

