Arduino不调用构造函数预留对象内存的实现问题及方案咨询
DelayedInit实现错误点
- get()方法无有效返回值:你写的
T& get() const { memory.obj; }仅执行了表达式没有返回值,属于典型的未定义行为,编译器会返回非法地址,调用方法时直接踩内存导致锁死。 - 未构造对象直接执行赋值:
*up = Button(2, true)是调用Button类的拷贝赋值运算符,但此时预留内存里还没有构造出合法的Button对象,对未初始化内存执行赋值操作完全非法。 - Union成员未正确激活:C++标准规定union同一时间仅能有一个激活的成员,你初始化时激活的是
memory数组,要使用obj成员必须通过定位new显式构造对象,完成成员激活。
修正后的DelayedInit实现
template<typename T> union MemoryOf { uint8_t memory[sizeof(T)]; T obj; }; template<typename T> struct DelayedInit { private: mutable MemoryOf<T> storage; bool initialized = false; public: DelayedInit() = default; ~DelayedInit() { if (initialized) { storage.obj.~T(); } } // 禁止拷贝构造/赋值,有需求可自行补充移动实现 DelayedInit(const DelayedInit&) = delete; DelayedInit& operator=(const DelayedInit&) = delete; // 显式构造对象接口,直接传入构造参数,无需临时对象 template<typename... Args> void construct(Args&&... args) { if (initialized) { storage.obj.~T(); } // 定位new:在预留内存上构造T对象,激活obj成员 new (&storage.obj) T(static_cast<Args&&>(args)...); initialized = true; } T& get() { return storage.obj; } const T& get() const { return storage.obj; } T* operator->() { return &get(); } const T* operator->() const { return &get(); } T& operator*() { return get(); } const T& operator*() const { return get(); } explicit operator bool() const { return initialized; } };
正确使用方式
DelayedInit<Button> up, enter, down; void setup() { up.construct(2, true); enter.construct(3, true); down.construct(4, true); } void loop() { if (up->just_pressed()) { // 业务逻辑 } }
替代方案
如果你的Arduino工具链支持C++17及以上标准,可以直接使用std::optional,语义和上述实现完全一致,且无额外动态内存开销,不需要自己维护容器代码。
内容的提问来源于stack exchange,提问作者Facundo
相关产品推荐
相关产品推荐

