2014-12-04 51 views
0

假設我有一個具有指針數組的類,並且我有一個方法將指針解引用並將其作爲引用返回。我想允許方法調用者調用指針指向的對象的非const方法,但也想保護我自己免受調用者改變指針指向的內容的影響。如果我返回一個const引用,我必須將許多指針對象的方法標記爲const,因此它的許多類成員變量都是可變的。過度使用可變增強安全性?

  1. 這是不好的做法?如果是這樣,我該如何解決這個問題?
  2. 過度使用可變性會有性能損失嗎?

例子:

#include <iostream> 
#include <array> 
#include <memory> 

class Counter 
{ 
public: 
    Counter(); 
    void hit() const; 
    void reset(); 
    unsigned count() const; 
private: 
    mutable unsigned count_; 
}; 

Counter::Counter() : count_(0) {} 

void Counter::hit() const { ++count_; } 

void Counter::reset() { count_ = 0; } 

unsigned Counter::count() const { return count_; } 

class CircularArray 
{ 
public: 
    CircularArray(); 
    const Counter& next() const; 
private: 
    mutable unsigned i_; 
    std::array<std::unique_ptr<Counter>, 3> arr_; 
}; 

CircularArray::CircularArray() : i_(2) 
{ 
    arr_[0] = std::unique_ptr<Counter>(new Counter); 
    arr_[1] = std::unique_ptr<Counter>(new Counter); 
    arr_[2] = std::unique_ptr<Counter>(new Counter); 
} 

const Counter& CircularArray::next() const { return *arr_[(i_ = (i_ + 1) % 3)]; } 

int main() 
{ 
    CircularArray circular; 
    const Counter* p; 
    p = &circular.next(); 

    p->hit(); 
    p->hit(); 

    Counter c; 
    //*p = c; // <-- Want to prevent this 
} 
+1

爲了達到這個目的而不是*濫用*'mutable',爲什麼不直接刪除賦值操作符呢? – Rufflewind 2014-12-04 05:16:48

+0

賦值運算符只是另一個成員函數。沒有什麼特別的。它像任何其他非const成員函數一樣修改'* this'。爲什麼選擇它?如果不適合公共使用,則不要公開。 – 2014-12-04 06:02:15

+0

我對這個問題有點困惑。你有你的CircularArray,其中包含ptrs到一系列計數器。您希望允許非常量訪問其中一個Counter個人。我正確地認爲你想避免的是調用者不會將另一個數組元素完全替換爲另一個實例? (「調用者改變指針指向的內容」)。他們無論如何都無法做到這一點,你沒有返回指針指針 – harmic 2014-12-04 06:08:19

回答

1

爲了延長我在說什麼,存在濫用mutable這是沒有意義的。如果這是你想要阻止:

class Counter 
{ 
    void operator=(const Counter&) = delete; 
    // ... 
}; 

記住,賦值運算符不影響身份:

*p = /* ... */; 

話,就可以更容易地通過刪除Counter賦值操作符完成對象:它不改變它的地址。在語義上,涉及修改this對象的任務以複製另一個對象的狀態。事實上,即使您使用賦值運算符莫名其妙禁止我,我還可以這樣做:

// a very inefficient way of performing `*p = c` 
p->reset(); 
while (p->count() != c.count()) 
    p->hit(); 

這實現了完全相同的結果作爲執行任務,雖然很笨拙和低效。

執行賦值與調用一個接受單個參數類型爲const Counter&的非const成員函數沒有區別。假設你可以重新定義賦值運算符,如果你想要做什麼都不會(儘管如此,這將是一個壞主意)。