Константный вектор неконстантных объектов

При определении функции в интерфейсе:

virtual void ModifyPreComputedCoeffs ( std::vector < IndexCoeffPair_t > & model_ ) = 0;

мы хотим указать, что векторная модель_ не должна изменяться в том смысле, что операции push_back etc не должны выполняться над вектором, но объекты структуры IndexCoeffPair_t в модели_ могут быть изменены. Как мы должны указывать это?

virtual void ModifyPreComputedCoeffs ( const std::vector < IndexCoeffPair_t > & model_ ) = 0;

не работает. Думаю.

Ответы

Ответ 1

Концепция const-correctness С++ - это метод IMO, переоцененный. То, что вы только что обнаружили, является одним из больших ограничений, которые он имеет: он не масштабируется по составу. Чтобы иметь возможность создавать константный вектор неконстантных объектов, вам необходимо реализовать свой собственный векторный тип. Обратите внимание, что, например, даже стандартная библиотека должна была вводить новые типы для const_iterators.

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

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

Вы когда-нибудь задавались вопросом, почему большинство языков (в том числе разработанных после С++) не реализовали эту идею?

Ответ 2

Вместо того, чтобы передавать вектор в функцию, выполните то, что делает стандартная библиотека, и вместо этого передайте пару итераторов.

virtual void ModifyPreComputedCoeffs ( std::vector < IndexCoeffPair_t >::iterator & model_begin, std::vector < IndexCoeffPair_t >::iterator & model_end )

Ответ 3

Вероятно, это будет в С++ 14 как std:: dynarray.

Фактически, если размер фиксируется во время компиляции, вы можете использовать std:: array. Но это, вероятно, больше используется для таких вещей, как встроенное программирование, буферы, матрицы и т.д., Так как часто вы не знаете нужный размер до времени исполнения или хотите, чтобы он настраивался.

Ответ 4

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

Пример:

class IndexCoeffPair_t {
public:
    void changeX(int newVal) const {
        x = newVal;
    }

private:
    mutable int x;
};

Ответ 5

Вы можете попробовать создать const std::vector<YouType*>. Тогда вы не можете изменить вектор, но вы можете изменить объекты внутри вектора. Но будьте точны, потому что вы будете изменять оригинальные объекты, а не копии.

Использование умных указателей или необработанных указателей зависит от ваших вариантов использования: у вас есть собственный вектор или просто вектор наблюдателей.

Ответ 6

Вот общая версия ответа MahlerFive:

template<typename T>
class Mutable {
    mutable T m_val;
public:
    constexpr Mutable(T const& val) : m_val(val) { }
    constexpr Mutable(T&& val) : m_val(val) { }

    // note: all member functions are 'const'
    constexpr Mutable const& operator=(T const& val) const {
        m_val = val;
        return *this;
    }
    constexpr Mutable const& operator=(T&& val) const {
        m_val = val;
        return *this;
    }

    constexpr operator T&() const {
        return m_val;
    }
};

Затем вы можете использовать std::vector<Mutable<T>> const в вашем коде, который в основном будет вести себя как задумано.