RAII:在const方法中初始化数据成员

Tho*_*ews 3 c++ const-correctness lazy-evaluation

RAII中,资源在访问之前不会初始化.但是,许多访问方法被声明为常量.我需要调用mutable(非const)函数来初始化数据成员.

示例:从数据库加载

struct MyClass
{
  int get_value(void) const;

  private:
     void  load_from_database(void); // Loads the data member from database.

     int m_value;
};

int
MyClass ::
get_value(void) const
{
  static bool value_initialized(false);
  if (!value_initialized)
  {
    // The compiler complains about this call because
    // the method is non-const and called from a const
    // method.
    load_from_database();
  }
  return m_value;
}
Run Code Online (Sandbox Code Playgroud)

我的原始解决方案是将数据成员声明为mutable.我宁愿不这样做,因为它表明其他方法可以改变成员.

如何转换load_from_database()语句以摆脱编译器错误?

Mat*_* M. 20

这不是RAII.在RAII中,您将在构造函数中初始化它,这将解决您的问题.

所以,你在这里使用的是Lazy.无论是懒惰的初始化还是懒惰的计算.

如果你不使用mutable,那么你就是一个受伤的世界.

当然你可以使用a const_cast,但如果有人这样做了:

static const MyClass Examplar;
Run Code Online (Sandbox Code Playgroud)

编译器决定它是只读内存的一个很好的候选者?那么,在这种情况下,效果const_cast是不确定的.充其量,没有任何反应.

如果你仍然希望继续这const_cast条路线,那就R Samuel Klatchko去做吧.

如果你考虑并认为可能有更好的选择,你可以决定包装你的变量.如果是在它自己的阶级,只有3种方法:get,setload_from_database,那么你就不会担心被mutable.

  • 有一个upvote指出这不是RAII (4认同)
  • ...而且反对const_cast几乎总是错的 (4认同)

Sta*_*ked 5

您基本上是实现缓存机制.我个人认为将缓存数据标记为可变是可以的.


Jer*_*fin 5

正如Matthieu已经指出的那样,你在这里尝试做的事与RAII几乎没有关系(如果有的话).同样,我怀疑任何组合constmutable真正会有所帮助.constmutable修改类型,并同样适用于对该类型对象的所有访问.

您似乎想要的是少量代码具有写访问权限,而其他任何内容只能读取对该值的访问权限.鉴于C++(和大多数类似语言)的基本设计,正确的方法是将变量移动到自己的类中,少量代码需要写访问作为(或可能是朋友的一部分)的一部分. )那个班.世界其他地方通过类的接口(即,检索值的成员函数)获得只读访问权限.

MyClass你发布的(可能是剥离的)非常接近 - 你只需要自己使用它,而不是作为一个有很多其他成员的大班级的一部分.要改变的主要事情是1)名称从MyClass类似的东西lazy_int,2)(至少根据我的喜好)get_value()应该重命名为operator int().是的,m_value可能需要是可变的,但这不允许其他代码写入值,因为其他代码根本无法访问值本身.

然后,您将该类型的对象嵌入到更大的类中.该外部类中的代码可以将其视为一个int(在只读的基础上),这要归功于它operator int(),但不能写它,只是因为类没有给出任何方法.