具有延迟初始化的C++ const getter方法

Dav*_*eer 30 c++ lazy-loading const

为延迟初始化的成员变量实现getter方法并保持const正确性的正确方法是什么?也就是说,我想让我的getter方法成为const,因为在第一次使用它之后,它是一个普通的getter方法.这是第一次(首次初始化对象时)const不适用.我想做什么:

class MyClass {
  MyClass() : expensive_object_(NULL) {}
  QObject* GetExpensiveObject() const {
    if (!expensive_object_) {
      expensive_object = CreateExpensiveObject();
    }
    return expensive_object_;
  }
private:
  QObject *expensive_object_;
};
Run Code Online (Sandbox Code Playgroud)

我可以吃蛋糕吗?

Jam*_*ran 23

这很好,是这种做法的典型方式.

你必须声明expensive_object_mutable

mutable QObject *expensive_object_; 
Run Code Online (Sandbox Code Playgroud)

mutable 基本上意味着"我知道我在const对象中,但修改它不会破坏常量."

  • 我们正在讨论可能受保护/私有变量的实现细节.如果其他方法也能改变它,那有什么关系呢?其他方法也可以提取const转换并进行更改.没有使用mutable没有额外的封装.然而,使它变得可变告诉读者类定义有价值的知识. (5认同)
  • @ user275455:Const-safety对类维护者以及类的客户端很有帮助.这很重要,因为您不希望在const方法中意外地改变成员.如果没有可变性,编译器将为您捕获.你说客户不应该担心受保护/私人的细节(真实),但是你面对面说并且说可变私有变量的声明对客户有价值(不是真的). (4认同)
  • 您可以很容易地让另一个维护者在声明中看到const,认为它根本不会发生变化,依赖于此并以此方式引入错误.我对const转换解决方案也没有任何问题,但我确实认为对可变解决方案的贬低是错误的;每种方法都有其优点.在我看来,可变解决方案有更多的优点,但只是略有不同. (2认同)
  • @ user275455:这是一个非常明确的解释.谢谢.我将收回我的downvote,并在将来保存它们,以获得严格错误的答案,并让其他人的赞成归类为"最佳". (2认同)

Ken*_*oom 19

如果经常这样做,我建议将James Curran的答案封装成自己的类:

template <typename T>
class suspension{
   std::tr1::function<T()> initializer;
   mutable T value;
   mutable bool initialized;
public:
   suspension(std::tr1::function<T()> init):
      initializer(init),initialized(false){}
   operator T const &() const{
      return get();
   }
   T const & get() const{
      if (!initialized){
         value=initializer();
         initialized=true;
      }
      return value;
   }
};
Run Code Online (Sandbox Code Playgroud)

现在在代码中使用它,如下所示:

class MyClass {
  MyClass() : expensive_object_(CreateExpensiveObject) {}
  QObject* GetExpensiveObject() const {
    return expensive_object_.get();
  }
private:
  suspension<QObject *> expensive_object_;
};
Run Code Online (Sandbox Code Playgroud)


bsh*_*lds 6

expensive_object_可变的.


Jon*_*ric 5

const_cast在那个特定的地方使用to side-step const 。

QObject* GetExpensiveObject() const {
  if (!expensive_object_) {
    const_cast<QObject *>(expensive_object_) = CreateExpensiveObject();
  }
  return expensive_object_;
}
Run Code Online (Sandbox Code Playgroud)

恕我直言,这比制作更好,expensive_object_ mutable因为您不会在所有其他方法中失去 const 安全性。

  • 抛弃连续性和修改对象是未定义的行为,除非对象实际上不是常量。您无法从此处的用法中看出这一点。 (7认同)
  • @Martin:那会教我在说出口之前先阅读标准 =) 5.2.11.7:“[注意:根据对象的类型,通过指针、左值或指向数据成员的指针的写操作由 a丢弃 const 限定符的 const_cast 68)可能会产生未定义的行为(7.1.5.1)。]” 7.1.5.1.4:“除了可以修改声明为可变的任何类成员(7.1.1)之外,任何试图修改 const 的尝试对象在其生命周期 (3.8) 中会导致未定义的行为。” 这可能是为了允许诸如放置在写保护内存中之类的东西,猜测一下? (3认同)
  • 我不是反对者,但我相信如果 MyClass 实例被创建为 `const`,这可能会导致未定义的行为。 (2认同)
  • @乔恩-埃里克。那不能解决它。我想问题是当你将一个对象声明为 const (没有可变成员)时,编译器可能会决定将该对象放在某个只读内存页面上。见 http://www.parashift.com/c++-faq-lite/const-correctness.html (2认同)