2017-04-11 57 views
2

我想要做這樣的事情:如何判斷一個函數是否被用來修改信息?

class bar{ 
public: 
    bool edit; 
    int foo[]; 


    //If the intention is to change some value in foo: 
    float & operator [] (int i){ 
     edit = true; 
     return foo[i]; 
    } 

    //But if I just want to read 
    float & operator [] (int i){ 
     return foo[i]; 
    } 
} 

我想這樣做,如果這是可以做到的正確途徑。

簡單的解決方案是存儲兩個向量,舊的和新的,並每次檢查它們。但我想要一個高效的解決方案,而不必每次更改某個值時手動更改「編輯」。

也許有r值和l值?

編輯: 的想法是,例如,如果我將檢查「富」的總和,存儲的價值,所以我沒有,我想知道的總和每次檢查FOO,只有當FOO已改性。

+0

編寫一個跟蹤修改的類型。把這些放在你的陣列中。 – molbdnilo

+0

問題是代碼的某些部分可能會選擇可修改的版本,但不會對其進行修改。是定義一個浮動類與=運算符標誌着它已被修改一個選項? – cup

+1

您可能不希望將非常量引用返回到死值,因爲使用該值是未定義的行爲。你應該有函數對數組元素類型的返回引用:'float foo []; float&operator []'或'int foo []; int&operator []' – Caleth

回答

1

你可以讓這些僞裝成float,但有記錄的附加語義的代理對象,如果該值已經改變:

#include <cassert> 

class bar { 
    struct Proxy { 
     Proxy(float &f, bool &edit) 
      : f{f} 
      , edit{edit} {} 
     template <class T> 
     float &operator=(const T &t) { 
      edit = true; 
      f = t; 
      return f; 
     } 

     template <class T> 
     float &operator+=(const T &t) { 
      edit = true; 
      f += t; 
      return f; 
     } 

     template <class T> 
     auto operator+(const T &t) const { 
      return f + t; 
     } 

     operator float(){ 
      return f; 
     } 

     //TODO: add all other relevant operators 

     private: 
     float &f; 
     bool &edit; 
    }; 

    public: 
    bool edit{false}; 
    float foo[42]{}; 

    //If the intention is to change some value in foo: 
    Proxy operator[](int i) { 
     return {foo[i], edit}; 
    } 

    //But if I just want to read 
    float operator[](int i) const { 
     return foo[i]; 
    } 
}; 

int main() { 
    bar b; 
    float f = b[0]; 
    assert(b.edit == false); 
    b[0] += f; 
    assert(b.edit == true); 
} 

存在一些問題,如全部實現所需的代碼float操作符和一些隱式轉換被禁用,因爲我們添加了用戶定義的轉換,並且添加0將設置edit標誌。
此外,人們必須更多地考慮應如何定義操作符,而不是像我在示例中那樣在邊緣情況下展示正確行爲,例如Proxy + Proxy或與其他類型的交互。

1

在C++中的函數可以被標記const,以表明它不應該改變的信息:

class bar{ 
public: 
    bool edit; 
    int foo[]; 


    //If the intention is to change some value in foo: 
    float & operator [] (int i){ 
     edit = true; 
     return foo[i]; 
    } 

    //But if I just want to read 
    float operator [] (int i) const { 
     return foo[i]; 
    } 
} 

還要注意,用於const函數的返回類型是不同的 - 返回float而非float&參考。簡單地將該功能標記爲const實際上並不能阻止它改變班級中的信息。相反,此功能用於const副本或類本身的引用。

+2

問題在於,即使float未被修改,也會選擇非const版本。你不需要修改該值就可以使用'std :: as_const(some_bar)[i]',並且在那時你可能有函數float&get_editable(i)'和'float get_not_editable(i )'。 – nwp

+0

我已經考慮過了,但我不認爲它解決了這個問題,因爲我想修改和閱讀「bar」的同一副本。 –

1

一般來說,正如所問,你不能做你想做的事 - 因爲C++不允許你重載引用是否被修改。我的建議是:

class bar{ 
public: 
    bool edit; 
    int foo[]; 


    // If I just want to read - use index operator. 
    float operator [] (int i) const { 
     return foo[i]; 
    } 

    //If the intention is to change some value in foo: 
    float & get_ref(int i){ 
     edit = true; 
     return foo[i]; 
    } 
} 

換句話說允許bar_obj[i]得到一個只讀的值,但強制使用get_ref得到修改的參考。這仍然不能阻止別人寫:

std::cout << bar_obj.get_ref(12); 

時返回的值是不是實際上修改 - 所以不這樣做呢!

請注意,operator[]可能會返回const T&如果您的實際使用情況不是浮動。

0

當您通過引用獲取時,不能保證您實際設置了一個值。我會明確地創建一個getset功能編輯變量的狀態:

class bar{ 
public: 
    bool edit; 
    int foo[]; 

    float get(int i) { return foo[i]; } 
    void set(int i, float v) { 
     edit = true; 
     foo[i] = v; 
    } 
} 

這可以保證所有的寫操作將被edit變量,你不能用當前的方法確保被反射(或其他參考建議提供)。

0

您可以在常量上重載operator []std:: containers這樣做。

N.B.您可能不希望將非常量引用返回到死值,因爲使用該值是未定義的行爲。

class bar{ 
public: 
    bool edit; 
    vector<float> foo; 

    // Mutable float available only to mutable bar's 
    float & operator [] (int i){ 
     edit = true; 
     return foo[i]; 
    } 

    // Has to be const float &, as const bar propogates const-ness to it's members 
    const float & operator [] (int i) const{ 
     return foo[i]; 
    } 
} 
0

您可以使用靜態成員作爲僞通知符來跟蹤功能訪問。當然,您需要知道爲了實現這一目標必須跟蹤哪個功能。

所以

class bar{ 
public: 
    static int mod_count; //pseudo_notifier 
    int foo[]; 


    //If the intention is to change some value in foo: 
    float & operator [] (int i){ 
     mod_count++; 
     return foo[i]; 
    } 

    //But if I just want to read 
    float & operator [] (int i){ 
     return foo[i]; 
    } 

    int getcount() 
    { 
     return mod_count; 
    } 

}; 
bar::mod_count = 0; 

int main() 
{ 
    int count = bar::getcount(); 
    bar mybobj; 
    /* 
    do whatever operations you plan to do 
    myobj[someidx] = 29; 

*/ 
    if(bar::getcount() > count) 
    //I know my function has modified the object state 

} 
0

我會用明確的getter和setter方法(並進行數據的私有性),而不是超載[]操作:

class bar 
{ 
    private: 
     bool edit; 
     int foo[]; 

    public: 
     float get_val(int i) const { return foo[i]; } 
     void set_val(int i, float v) 
     { 
      // Only if new value is different from current value 
      if (foo[i] != v) 
      { 
       edit = true; 
       foo[i] = v; 
      } 
     } 

這樣可以確保所有的變化被捕獲,並且沒有真正改變任何東西的set操作的誤報(例如,將foo[n]設置爲它已經包含的相同值)。並且通過使您的數據成員處於隱私狀態,您可以防止任何人編寫更改foo而沒有edit也會被設置的代碼。

相關問題