【问题标题】:Temporarily modifying fields in a const member function临时修改 const 成员函数中的字段
【发布时间】:2017-04-18 20:09:24
【问题描述】:

假设我们有一个类A 和一个成员函数f。 对于外界来说,f 只是简单地计算一个值,而不修改A 的任何内容;但在实现中,它确实临时修改了A

class A
{
    int f() const
    {
        tiny_change(b); // since copying "b" is expensive
        int result = compute(b);
        tiny_recover(b); // "b" backs to the original value
        return result;
    }

    B b;
}

当然上面的代码不能编译。以下是我知道的两种解决方法:

  1. const_cast<A*>(this)->b
  2. mutable B b;

这些解决方案都不是完美的。解决方案1涉及UB当A的实例本身为const时;并且解决方案 2 将可变性暴露给整个类,因此它不能防止编码人员意外修改其他 const 成员函数中的 b

const_cast 是“本地”,但可能会触发 UB; mutable 是内存安全的,但也太“全局”了。

那么有没有第三种解决方案,还是我理解错了?

【问题讨论】:

  • 你不能代替tiny_change(b) 开发tiny_change(result) 并在未更改的B 上计算结果。
  • 你不能重载compute 来获取“小零钱”并使用它来代替b 的任何值吗? B 显然与您的类的逻辑常量有关,而不仅仅是按位。在这种情况下,这两种解决方案都是 hack。
  • @Zereges 这些函数在我的例子中不是同态的
  • @StoryTeller 在我的情况下,B 是一个大数组,任何数组元素都可能发生“小变化”。 compute(b) 是基于 CPU 敏感的递归,所以直接修改 b 可能是最便宜的。
  • 在多线程上下文中小心这种方法。 const 成员函数通常是线程安全的。如果您要更改b,则情况并非如此,您需要一个互斥锁来保证线程安全。

标签: c++ mutable const-cast


【解决方案1】:

一种可能性是将B 封装在一个拥有mutable 的类中,但当它是const 时,通常只允许const 访问,除非它与A::f 成为朋友。例如像这样(未经测试的代码):

class A
{
  int f() const;
  int g() const; // some function without exclusive access

  class B_wrapper
  {
    friend int A::f() const;
  public:
    B& get() { return object; }
    B const& get() const { return object; }
  private:
    B& get_mutable() const { return object; }
    mutable B object;
  };
  B_wrapper bw;
};

int A::f() const
{
  B& b = bw.get_mutable(); // allowed due to friend declaration
  tiny_change(b); // since copying "b" is expensive
  int result = compute(b);
  tiny_recover(b); // "b" backs to the original value
  return result;
}

int A::g() const
{
  // B& b = bw.get_mutable();
  //   -> not allowed because B_wrapper::get_mutable() is private
  // B& b = bw.get();
  //   -> not allowed because get() const returns a const reference
  B const& b = bw.get();
  // without casts, only const interface to b is available
}

【讨论】:

    猜你喜欢
    • 2021-01-08
    • 2011-11-15
    • 1970-01-01
    • 2017-10-11
    • 2013-05-17
    • 1970-01-01
    • 2012-12-12
    • 2017-01-08
    相关资源
    最近更新 更多