You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 06:15:07