3

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

示例:从数据库加载

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;
}

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

我将如何load_from_database()转换语句以消除编译器错误?

4

6 回答 6

20

这不是 RAII。在 RAII 中,您将在构造函数中对其进行初始化,这将解决您的问题。

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

如果您不使用mutable,您将进入一个受伤的世界。

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

static const MyClass Examplar;

并且编译器认为它是只读内存的良好候选者?好吧,在这种情况下, 的效果const_cast是不确定的。充其量,什么也不会发生。

如果您仍想继续该const_cast路线,请照常R Samuel Klatchko进行。

如果您仔细考虑并认为可能有更好的选择,您可以决定包装您的变量。如果它在自己的类中,只有 3 个方法:和get,那么你就不用担心它是.setload_from_databasemutable

于 2010-03-19T16:44:20.873 回答
5

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

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

您发布的(大概是精简的)MyClass非常接近正确 - 您只需要单独使用它,而不是作为具有许多其他成员的更大类的一部分。要更改的主要内容是 1) 名称 fromMyClass到类似lazy_int2) (至少根据我的喜好)get_value()可能应该重命名为operator int(). 是的,m_value可能需要是可变的,但这不允许其他代码写入该值,因为其他代码根本无法访问该值本身。

然后,您将该类型的对象嵌入到更大的类中。由于它的 ,该外部类中的代码可以将其视为 int (在只读的基础上)operator int(),但不能编写它,仅仅是因为该类没有提供任何方法。

于 2010-03-19T18:15:15.797 回答
5

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

于 2010-03-19T16:47:02.623 回答
4

[看妈妈!没有演员表!:))]

struct DBValue 
{
  int get_value();

private:
  void load_from_database();
  int value;
};

struct MyClass 
{
  MyClass(): db_value(new DBValue()) {}
  ~MyClass() { delete db_value; } 

  int get_value() const;

private:
  DBValue * const db_value;
};

int MyClass::get_value() const
{
  return db_value->get_value(); // calls void load_from_database() if needed
}

这个想法是在政治上正确MyClassconst方法不会改变任何东西,而是通过 const 指针调用聚合对象的方法和const非方法。const

于 2010-03-19T17:29:18.583 回答
1

不要在这里使用 const_cast ,否则你是在自找麻烦。在这种情况下使用 mutable 应该不是问题,但如果探查器没有提出其他建议,那么我认为用户看到构造成本高昂的对象比第一次调用昂贵的访问器方法时不会那么惊讶.

于 2010-03-19T16:57:00.167 回答
0

如果您的方法更改了对象的状态(例如,通过更改底层数据库的状态),那么该方法不应该是 const。在这种情况下,您应该有一个单独的非 constload方法,必须在调用constgetter 之前调用该方法。

这种方法既不需要const_castnot mutable,也会使潜在的昂贵操作显式化。

于 2010-03-19T16:57:12.967 回答