2016-12-04 131 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 
}