是否存在无默认构造函数的unique_ptr?如何强制其初始化?
关于std::unique_ptr默认构造与强制初始化的问题解答
为什么std::unique_ptr要提供默认构造函数?
标准库这么设计主要是两个核心原因:
- 满足STL容器的兼容性要求:很多STL容器的API要求元素类型支持默认构造,比如批量创建vector元素、resize操作等场景,需要先构造空的unique_ptr占位,后续再赋值有效指针。
- 支持延迟初始化场景:部分业务逻辑里,指针指向的对象无法在类构造阶段完成创建,需要等后续配置加载、依赖就绪后再初始化,默认构造的空unique_ptr可以满足这类需求。
C++标准库的设计原则是优先提供灵活性,不会强制约束开发者的编码习惯,因此不会默认禁用默认构造。
有没有强制要求初始化的非空unique_ptr实现?
标准库暂时没有提供内置的valid_unique_ptr这类类型,但业界已经有非常成熟的落地方案:很多公司的内部基础库都实现了非空智能指针包装,比如Abseil库的absl::NonNull模板,就可以直接套在unique_ptr外层,强制要求初始化时传入非空值,从编译层面避免空指针问题。
应该继承还是包装unique_ptr实现强制初始化?
绝对不要继承std::unique_ptr,包括所有STL智能指针都没有虚析构函数,继承后如果通过基类指针销毁派生类实例会触发未定义行为。
正确的方案是采用组合(包装)的方式,把unique_ptr作为私有成员,对外暴露必要的访问接口,同时删除默认构造函数,只保留接受有效指针的构造函数,必要时可以加空指针检查的断言。
下面是一个简单的实现示例:
template <typename T> class non_null_unique_ptr { public: // 删除默认构造,禁止空实例 non_null_unique_ptr() = delete; // 强制要求传入指针,构造时做空检查 explicit non_null_unique_ptr(T* ptr) : m_ptr(ptr) { assert(ptr != nullptr && "non_null_unique_ptr cannot be initialized with null"); } // 支持从unique_ptr移动构造 explicit non_null_unique_ptr(std::unique_ptr<T>&& ptr) : m_ptr(std::move(ptr)) { assert(m_ptr != nullptr && "non_null_unique_ptr cannot be initialized with null"); } // 暴露指针访问接口,和原生unique_ptr用法对齐 T* operator->() const noexcept { return m_ptr.get(); } T& operator*() const noexcept { return *m_ptr; } std::unique_ptr<T>& get() noexcept { return m_ptr; } const std::unique_ptr<T>& get() const noexcept { return m_ptr; } private: std::unique_ptr<T> m_ptr; };
用到你给出的示例里,代码就会变成下面的样子,如果忘记初始化m_timer,编译阶段就会直接报错:
#include "XTimerFactory.h" struct MyClass { MyClass(XTimerFactory& timerFactory) : m_timer(timerFactory.createTimer()) // 这里如果漏写,编译会直接报错,不需要等到运行期崩溃 { } void start() { m_timer->start(100); } private: non_null_unique_ptr<XTimer> m_timer; };
内容的提问来源于stack exchange,提问作者Pawl Driveklepp
相关产品推荐
相关产品推荐

