2016-12-04 29 views
2

假设我们有一个带有成员函数f的类A。 对外界来说,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;

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

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

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

+0

难道你不是'tiny_change(b)'开发一种'tiny_change(result)'并计算未改变的'B'的结果。 – Zereges

+0

难道你不能只重载'计算'采取“小变化”,并使用它,而不是“b”有什么值? “B”显然与你的课程的逻辑常量有关,而不仅仅是按位。在这种情况下,两种解决方案都是黑客。 – StoryTeller

+0

@Zereges这些函数在我的情况下不是同态的 – rolevax

回答

2

一种可能性是在具有它mutable一个类来封装B,但是当它是常量通常只允许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 
}