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

C++编译错误:构造函数中非const引用初始值必须为左值

问题描述

我正在编写一个程序,其中包含定义组件行为的Component虚类,该组件需通过总线访问设备寄存器。寄存器操作由独立于总线类型的Register虚类定义,派生类RegisterI2C实现了I2C总线的寄存器访问函数。ComponentI2C类对应使用I2C总线的组件,我在该类中定义component_reg函数时调用RegisterI2C的构造函数,编译时出现错误:initial value of reference to non-const must be an lvalue C/C++(461)。我尝试过多种类型转换但未找到解决方案,且无法将component_reg改为返回指针,恳请各位提供解决思路。

代码示例:

class Component;
class Register {  // defines access method to registers
 public:
  Register(Component *parent, int reg) : parent_(parent), register_(reg) {}
  virtual int read() = 0;  // read the register
  Component *const parent_; // parent component
  int register_; // the register to operate on
};
class Component {  // defines what a component do.Uses Register functions
  virtual Register &component_reg(int reg) = 0; // return a Register we use for op on comp
};
class I2C {};  // provides I2C busfunctions
class ComponentI2C;
class RegisterI2C : public Register {  // implement Register func for I2C bus
 public:
  RegisterI2C(Component *parent, int reg) : Register(parent, reg) {}
/* use I2C class methods through downcasting Component to ComponentI2C */
  int read() override { return 0; }
};
class ComponentI2C : public Component, public I2C {
 public:
  RegisterI2C &component_reg(int reg) override { return {this, reg}; }; // **PROBLEM HERE**
};
解决思路

编译错误的核心原因是:你试图返回一个临时对象的非const引用。{this, reg}构造的是匿名RegisterI2C临时对象,临时对象属于右值,C++不允许将非const引用绑定到右值——临时对象会在表达式结束后立即销毁,引用会变成悬空引用,触发未定义行为。

针对不能返回指针的限制,提供两种可行方案:

方案1:在ComponentI2C中缓存寄存器对象

如果每个寄存器对应唯一的RegisterI2C实例,用容器缓存已创建的对象,保证返回的是长期存在的实例引用:

#include <unordered_map>

class ComponentI2C : public Component, public I2C {
 private:
  std::unordered_map<int, RegisterI2C> reg_cache_;
 public:
  RegisterI2C &component_reg(int reg) override {
    // 查找缓存,不存在则创建新对象
    auto it = reg_cache_.find(reg);
    if (it == reg_cache_.end()) {
      it = reg_cache_.emplace(reg, RegisterI2C(this, reg)).first;
    }
    return it->second;
  }
};

这种方式既满足返回引用的要求,又避免了悬空引用问题,适合大多数场景。

方案2:修改为返回const引用(只读场景适用)

如果你的场景只需要对寄存器进行读操作,不需要修改RegisterI2C对象,可以将虚函数改为返回const Register&,此时合法绑定临时对象:

// 修改Component类的虚函数定义
class Component {
  virtual const Register &component_reg(int reg) = 0;
};

// 对应修改ComponentI2C的实现
class ComponentI2C : public Component, public I2C {
 public:
  const RegisterI2C &component_reg(int reg) override { return RegisterI2C(this, reg); }
};

注意:临时对象的生命周期会延长到引用的生命周期结束,但该方案仅适用于只读场景,且禁止通过const_cast去除const属性修改对象,否则会触发未定义行为。

内容的提问来源于stack exchange,提问作者DrCoolZic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:29:59