Чрезмерное использование mutable для повышения безопасности?

0

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

  1. Это плохая практика? Если да, то как мне обойти это?
  2. Есть ли ограничение производительности для чрезмерного использования 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 для этой цели, то почему бы не просто удалить оператор присваивания?
  • 0
    Оператор присваивания - это просто еще одна функция-член. В этом нет ничего особенного. Это модифицирует *this точно так же, как любая другая неконстантная функция-член. Зачем выделять это? Если это не подходит для публичного использования, просто не делайте это публичным.
Показать ещё 3 комментария
Теги:
pointers
mutable
const

1 ответ

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&. Гипотетически, вы могли бы переопределить оператор присваивания, чтобы вообще ничего не делать, если хотите (хотя это была бы плохая идея).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню