嵌入式C++:用std::expected工厂函数避免析构函数重复调用
解决嵌入式C++中Timer_t工厂函数返回导致的重复析构问题
针对你遇到的makeTimer()返回std::expected<Timer_t, Error_t>时,移动构造引发两次析构的问题,这里提供一个无额外运行时开销、适配嵌入式场景的解决方案:让Timer_t成为移动-only类型,并利用自身硬件关联成员作为无效状态标识,在移动操作中转移资源所有权,确保只有最终持有资源的对象会触发反初始化。
具体实现
#include <expected> // 假设Error_t是你的错误类型枚举 enum class Error_t { INIT_FAILED }; struct Timer_t { private: // 用硬件定时器句柄作为核心成员,无效值设为0(根据实际硬件调整) uintptr_t timer_handle = 0; // 私有构造:仅由工厂函数调用,直接初始化句柄 explicit Timer_t(uintptr_t handle) : timer_handle(handle) {} Timer_t() = delete; // 隐藏默认构造 public: // 禁用拷贝操作,强制移动语义 Timer_t(const Timer_t&) = delete; Timer_t& operator=(const Timer_t&) = delete; // 移动构造:转移资源所有权,将源对象置为无效状态 Timer_t(Timer_t&& other) noexcept : timer_handle(other.timer_handle) { other.timer_handle = 0; } // 移动赋值:先清理当前资源(如果有效),再转移所有权 Timer_t& operator=(Timer_t&& other) noexcept { if (this != &other) { if (timer_handle != 0) { deinit_hardware_timer(timer_handle); // 硬件反初始化逻辑 } timer_handle = other.timer_handle; other.timer_handle = 0; } return *this; } // 析构函数:仅当句柄有效时执行反初始化 ~Timer_t() { if (timer_handle != 0) { deinit_hardware_timer(timer_handle); timer_handle = 0; } } // 工厂函数:返回std::expected,初始化失败时返回错误 static std::expected<Timer_t, Error_t> makeTimer() { uintptr_t handle = init_hardware_timer(); // 硬件初始化逻辑 if (handle == 0) { return std::unexpected(Error_t::INIT_FAILED); } return Timer_t(handle); } };
核心逻辑说明
- 移动-only约束:禁用拷贝构造和赋值,确保
Timer_t只能通过移动传递,避免不必要的对象复制。 - 资源转移与无效化:移动构造/赋值时,将源对象的硬件句柄转移给新对象,并把源对象的句柄设为无效值。这样被移动后的源对象在析构时,因为句柄无效,不会执行硬件反初始化操作。
- 无额外开销:完全利用
Timer_t自身的硬件关联成员(句柄)作为状态判断依据,不需要额外的布尔标志、引用计数等,没有任何运行时开销,完美适配嵌入式资源受限场景。 - 兼容性保障:即使编译器未开启返回值优化(RVO/NRVO),移动操作触发后也不会导致重复反初始化;同时严格遵循C20标准(
std::expected是C20特性),兼容主流嵌入式编译器。
内容的提问来源于stack exchange,提问作者Sickeroni
相关产品推荐
相关产品推荐

