Постоянная правильность и <random>

Каков правильный способ решения (в противном случае) постоянных функций, которые включают случайный генераторный вызов С++ 11 random-class? Если вы предпочитаете отказаться от флага постоянной функции или было бы лучше объявить генератор и распространение как изменчивые элементы вашего класса? Минимальным примером (не компиляцией) может быть:

#include <random>

class foo 
{
  std::mt19937 MyGenerator;
  std::normal_distribution<precision_type> gauss;
  double get_rnd() const {return gauss(MyGenerator);}
};

Ответ 1

Это зависит от того, какую семантику вы предоставляете для доступа const.

Для стандартных классов поточно-безопасный одновременный вызов const членов из нескольких потоков. Уходящие члены const, которые мутируют RNG, нарушат это, если RNG не полностью потокобезопасен (для использования не const).

Вам не нужно создавать классы одинаково, но другим разработчикам, вероятно, будет неловко обнаруживать классы, которые нельзя безопасно "читать" (вызывать const функции-члены) одновременно.

Один из вариантов состоит в том, чтобы предоставить два варианта - неконстантную версию, которая использует встроенный RNG, и версию const, которая принимает RNG по неконстантной ссылке. (Первый может вызвать второй, не требуется const_cast). Это реализует политику "платить только за то, что вам нужно" ориентировочно w.r.t, поскольку несколько потоков могут безопасно использовать объект, если каждый из них предоставляет локальный экземпляр RNG с потоком. Он также позволяет тестировать с использованием макетной реализации RNG, что, вероятно, даже более ценно.

Ответ 2

Это действительно зависит от того, чего вы хотите достичь, типичные стратегии включают в себя:

  • Воздействие изменчивости. Просто не отмечайте метод как const.

  • Внешний вид, чтобы показать изменчивость. Передайте изменчивые элементы (здесь генератор и распределение) в качестве параметров метода, подвергая использование изменчивости внутри, вызывающий отвечает за любые последствия потока.

  • Реализация "логической" константы. Если использование случайности не рассматривается как нарушение логической константы класса, вы можете просто объявить генератор и распределение как mutable; (если необходимо, то есть в многопоточном приложении, используйте мьютекс mutable)

Какую альтернативу вы выбираете, зависит от семантики, которую вы достигнете.

Ответ 3

Ключ mutable был разработан для этого типа случаев. Когда вы помечаете поле экземпляра случайного генератора этим модификатором, ему будет разрешено изменять его состояние даже в const методах окружающего класса.

В целом это кажется серой областью в зависимости от того, какой тип концепции представляет ваш класс. Если состояние генератора концептуально не имеет отношения к состоянию этого класса, чем это решение в порядке. В противном случае вы должны переосмыслить дизайн - если состояние генератора релевантно, чем метод, использующий его, не должен быть const.

Ответ 4

Я думаю, это зависит от вашего варианта использования. если вам нужно какое-то полностью детерминированное поведение, вам нужно сбросить флаг const, чтобы убедиться, что состояние вашего класса не может измениться, и ожидается, что он не будет изменен. Это может быть важно при написании кода или кода безопасности, подлежащих повторному тестированию.