2016-08-27 59 views
0

我寫了一個任務,要求我實現我自己的(基本)向量類。一個不尋常的要求是,我們必須提供一個函數,它給出向量中所有元素的和。這個函數應該緩存總和,所以如果向量沒有改變,後續的調用可以在恆定的時間內得到回答。我們如何區分使用重載[]運算符獲取和設置?

我遇到的問題是試圖找出,當它它已經改變。

#include <iostream> 

class MyVector { 
    int* v; 
    int size; 
    int totalSum; 
    bool upToDate; 
public: 
    MyVector(int size) : size{size}, totalSum{0}, upToDate{false} { 
     v = new int[size]; 
     for(int i = 0; i < size; i++) { 
      v[i] = 0; 
     } 
    } 

    // Set - should only be called as an lvalue 
    int& operator[](unsigned int i) { 
     upToDate = false; 
     std::cerr << "Set\n"; 
     return v[i]; 
    } 

    // Get - should only be called as an rvalue 
    int operator[](unsigned int i) const { 
     std::cerr << "Get\n"; 
     return v[i]; 
    } 

    // Get sum of array -- result is cached for performance 
    int sum() { 
     if(!upToDate) { 
      upToDate = true; 
      totalSum = 0; 
      for(int i = 0; i < size; i++) { 
       totalSum += v[i]; 
      } 
     } 
     return totalSum; 
    } 
}; 

int main() { 
    MyVector mv(3); 
    mv[0] = 1; 
    mv[1] = 2; 
    mv[2] = 3; 
    std::cout << "Sum " << mv.sum() << "\n"; 

    int first = mv[0]; 
    std::cout << "First element is " << first << "\n"; 

    std::cout << "Sum " << mv.sum() << "\n"; 
} 

我提供了兩個重載版本的[]操作符 - 一個用於獲取和一個用於設置。無論何時調用操作符的設置版本,我都假定該向量正在更改。

# Output 
Set 
Set 
Set 
Sum 6 
Set 
First element is 1 
Sum 6 

然而,似乎運營商的設置版本總是被調用,即使它被用作右值。

如何正確地重載[]運算符來區分它用於獲取和設置?

+0

來解決這一問題的方法是有缺陷的從非const的'operator []'版本返回的引用可以被調用者保存,並且稍後用於修改a繞過所有嘗試來檢測變化。我認爲嘗試解決問題的唯一方法就是通過返回代理對象,但這可能超出了作業的範圍。 –

回答

2

不是直接返回存儲int的引用,而是可以返回該引用的瘦代理包裝器,該包裝器可以監視變化。在大多數情況下,編譯器應該內聯並優化它(可以嘗試對其進行基準測試並進行比較)。

包裝類:

class Item { 
    int &value; 
    MyVector &myVector; 

public: 
    Item(int &value, MyVector &myVector) : value(value), myVector(myVector) {} 

    Item& operator=(int newvalue) { 
     std::cerr << "Set\n"; 
     value = newvalue; 
     myVector.upToDate = false; 
     return *this; 
    } 

    // TODO: Reimplement also operators like +=, -=, etc 
    // You can use boost helpers for that. 

    operator int() const { 
     std::cerr << "Get\n"; 
     return value; 
    } 
}; 

更改MyVector:

class MyVector { 
    // ... 

    Item operator[](unsigned int i) { 
     return Item(v[i], *this); 
    } 

    const int operator[](unsigned int i) const { 
     std::cerr << "Const Get\n"; 
     return v[i]; 
    } 

// ... 
} 

它可以準確地使用相同的方式:

int main() { 
    MyVector mv(3); 
    mv[0] = 1; 
    mv[1] = 2; 
    mv[2] = 3; 
    std::cout << "Sum " << mv.sum() << "\n"; 

    int first = mv[0]; 
    std::cout << "First element is " << first << "\n"; 

    std::cout << "Sum " << mv.sum() << "\n"; 
}