2014-12-04 9 views
0

포인터 배열이있는 클래스가 있다고 가정하고 포인터를 역 참조하고이를 참조로 반환하는 메서드가 있습니다. 메서드 호출자가 포인터가 가리키는 개체의 비 const 메서드를 호출 할 수 있도록하고 싶지만 포인터가 가리키는 포인터를 변경하는 호출자로부터 자신을 보호하려고합니다. const 참조를 반환하면 포인터 객체의 메서드 중 많은 부분을 const로 표시해야하므로 해당 클래스 멤버 변수 중 많은 수가 변경 가능해야합니다.보안을 강화하기 위해 변경 가능한 항목을 계속 사용 하시겠습니까?

  1. 이것은 나쁜 습관입니까? 그렇다면이 문제를 어떻게 해결할 수 있습니까?
  2. over-use mutable에 대한 성능 저하가 있습니까?

예 :

#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

+0

할당 연산자는 다른 멤버 함수 일뿐입니다. 특별한 것은 없습니다. 다른 모든 const 멤버 함수와 똑같이'* this'를 수정합니다. 왜 그것을 밖으로 단일? 공개 사용에 부적절한 경우 공개하지 마십시오. –

+0

나는 조금 혼란 스럽다. 카운터 배열에 ptrs가 포함 된 CircularArray가 있습니다. 카운터 개인 중 한 명에게 비 const 액세스를 허용하려고합니다. 당신이 피하려고하는 것은 호출자가 배열 요소 중 하나를 다른 인스턴스로 대체하지 않는다는 것입니다. ("포인터가 가리키는 부분을 변경하는 호출자"). 그들은 어쨌든 그것을 할 수 없을 것입니다, 당신은 포인터에 포인터를 반환하지 않습니다 – harmic

답변

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 멤버 함수를 호출하는 것과 다르지 않습니다. 가설 적으로, 당신은 원한다면 할당 연산자가 전혀 아무것도하지 못하게 재정의 할 수 있습니다 (나쁜 생각 일 것입니다).