2014-12-04 1 views
0

Предположим, у меня есть класс с массивом указателей, и у меня есть метод, который разыгрывает указатель и возвращает его в качестве ссылки. Я хочу, чтобы вызывающий метод вызывал неконстантные методы объекта, на который указывает указатель, но также хочет защитить себя от вызывающего, изменяющего то, на что указывает указатель. Если я верну ссылку на 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

+0

Оператор присваивания - это еще одна функция-член. В этом нет ничего особенного. Он изменяет '* this' точно так же, как и любая другая функция, не являющаяся константой. Зачем это выделять? Если это неприемлемо для общественного использования, просто не публикуйте его. –

+0

Я немного смущен вопросом. У вас есть CircularArray, который содержит ptrs для массива счетчиков. Вы хотите разрешить неконстантный доступ к одному из лиц, имеющих счетчик. Я правильно понимаю, что вы пытаетесь избежать того, что вызывающий не заменяет один из элементов массива вообще другим экземпляром? («вызывающий меняет то, на что указывает указатель»). Они все равно не смогут этого сделать, вы не возвращаете указатель на указатель – harmic

ответ

1

Чтобы продлить то, что я говорил, нет никакого смысла в злоупотреблении mutable для этого. Если это все, что вы хотите, чтобы предотвратить:

*p = /* ... */; 

, то это можно сделать гораздо проще, удалив оператор присваивания Counter:

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

Помните, что оператор присваивания не влияет на личность объект: он не меняет свой адрес. Семантически назначение, связанное с модификацией объекта this для репликации состояния другого объекта. На самом деле, даже если вы запрещаете мне использовать оператор присваивания как-то, я все еще мог это сделать:

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

Это достигается тот же результат, выполняя задание, хотя и очень неумело и нерационально.

Выполнение присваивания ничем не отличается от вызова функции non-const member, которая принимает один аргумент типа const Counter&. Гипотетически, вы могли бы переопределить оператор присваивания, чтобы вообще ничего не делать, если хотите (хотя это была бы плохая идея).

 Смежные вопросы

  • Нет связанных вопросов^_^