Подтвердить что ты не робот

Что не так с const?

Каковы известные недостатки const в С++ и С++ 0x?

4b9b3361

Ответ 1

Два основных вопроса, которые я часто встречал в новостных группах, - это

Я думаю, что последний может/должен поддерживаться языком.

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

Третий вопрос:

Приветствия и hth.,

Ответ 2

Единственное, что не так с const, это то, что он серьезно недооценен для многих разработчиков. Это один из лучших инструментов в С++ toolbox, очень четкий, но не опасный для себя.

Ответ 3

Основная проблема заключается в том, что вы должны ее написать. Он должен быть по умолчанию, и все изменяемые переменные или параметры должны быть указаны явно.

Ответ 4

Что не так с const заключается в том, что многие программисты, похоже, не в состоянии полностью его понять, а проект с половинной константой просто не работает. Это то, что вам нужно знать:

  • Foo vs. const Foo (или Foo const)
  • Foo& vs. const Foo& (или Foo const&)
    • reference-to-const привязывается ко всем видам вещей, а ссылки-не-const не
  • Foo* vs. const Foo* (или Foo const*)
    • переменные-указатели также могут быть Foo* const и const Foo* const (или Foo const* const)
  • void Foo::mutator() против int Foo::accessor() const
    • но элементы-указатели внутри функций-членов-констант по-прежнему указывают на не-const-объекты
    • поэтому мы можем случайно вернуть неконстантные данные из const-функции
  • iterator vs. const_iterator
    • переменными итератора также могут быть const iterator и const const_iterator

Переход на С++ с языка, который не имеет концепции const, довольно сложно, многие из них не видят точку.

Ответ 5

Проблема с const - это программисты, которые неправильно используют это непоследовательно

Ответ 6

Одна вещь, которая является "неправильной", заключается в том, что вы не можете преобразовать T ** в T const * const *, который должен быть разрешен, потому что это не опасно. Невозможно преобразовать T ** в T const **, это преобразование недействительно.

Я иногда упоминал, что const фактически является дешевым способом "разделить" ваш интерфейс на методы только для чтения и методы записи. Вероятно, это было бы нецелесообразно в С++. В Java было бы более практично иметь версии коллекций ReadOnly, хотя они не имеют const и где их типы коллекций более объектно ориентированы.

const-ness не распространяется: проблема заключается в том, что если я pImpl мой класс, константа не "проверяется" компилятором, то есть мой класс интерфейса может иметь метод "const", вызывающий неконстантный метод на pImpl и компилятор не будут жаловаться. Это потому, что единственное, что мой const-метод не гарантирует, - это изменить указатель на другой объект, и мой pImpl никогда не изменится. Это может быть даже указатель const (не указатель на const).

Отсутствие надлежащей ковариации между shared_ptr<T> и shared_ptr<const T> также может быть проблемой, хотя, как правило, я видел, что это не проблема, но разработчики обычно типизируют свои shared_ptrs и редко набирают значение shared_ptr для Уст. И они иногда передают const shared_ptr<T> & и думают, что они передают общий указатель на const T (как и для const T *), которым они не являются.

Ответ 7

"проблемы"?

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

В современных версиях gcc есть поддержка предупреждений при попытке применить переменную const к const. Я предлагаю вам оставить эти предупреждения включенными.

Единственное, на что нужно обратить внимание, это именно то, что вы отмечаете const; const char * foo() не совпадает с char * foo() const.

Ответ 8

Еще одна проблема, о которой еще не упоминалось, - это возможность плохо спроектированного интерфейса для отклонения const (даже при отсутствии отбрасываний).

Пример:

class TreeNode {
public:
    TreeNode& getParent() const { return *parent_; }
    TreeNode& getLeft()   const { return *left_;   }
    TreeNode& getRight()  const { return *right_;  }
private:
    //TreeNode has a pointer to the Tree to enable navigation of the tree.
    //Assume that other design constraints mean that this must be a pointer 
    //rather than a reference.
    TreeNode* parent_;
    TreeNode* left_;
    TreeNode* right_;
};
//This function demonstrates the ability for const to be subverted.
TreeNode& remove_const(TreeNode const& toRemoveConstFrom) {
    TreeNode& parent(toRemoveConstFrom.getParent());
    TreeNode& leftChild(parent.getLeft());
    TreeNode& rightChild(parent.getRight());
    return &toRemoveConstFrom == &leftChild ? leftChild : rightChild;
}

Непереходный характер const означает, что возможно иметь интерфейс, где неконстантная ссылка на объект может быть получена из ссылки const на объект. Это необходимо соблюдать при разработке интерфейсов.

Ответ 9

Большинство ответов ниже состояний, таких как "что не так с const, это то, что X люди делают Y". Это не ответы, а симптомы. В const это не так. Там едва ли что-то не так с const... Это неправильно с людьми, которые не могут RTFM.

Ответ 10

const отлично. const важен. const -корректность - это необходимое условие для хорошего API.

Тем не менее, есть две проблемы, которые у меня были с const, несколько раз.

  • Невозможно пометить переменную как const ретроактивно. Вы должны либо объявить переменный код, и в этом случае вы должны его инициализировать немедленно. Что делать, если код инициализации содержит if, хотя? У вас есть выбор либо опускать const (нежелательно), используя оператор ? вместо if (вредит читаемости). Java это правильно, переменные BTW - const не обязательно должны быть инициализированы сразу, их нужно просто инициализировать до их первого чтения, и их нужно инициализировать во всех ветвях if.

  • Невозможно указать, что объект, переданный по ссылке на функцию, не будет меняться в течение продолжительности вызова функции. const T& t не означает, что объект, на который указывает t, не изменится, но только то, что ссылка t не может быть использована для его изменения. Компилятор все же должен предположить, что любой вызов функции, который он не видит, может изменить объект. В некоторых случаях это предотвращает довольно много оптимизаций.

Ответ 11

Одна из проблем заключается в том, что язык также позволяет вам const_cast его, что в первую очередь поражает цель использования const.

Ответ 12

Одно дело, что все еще возможно подорвать его. то есть законно делать что-то вроде этого:

void foo(const inst& x)
{
   const_cast<int&> x = 3;
}

Вы можете даже использовать такие вещи, как memset, чтобы подорвать его без явного const_cast.

Это компромисс между наличием компилятора const и возможностью некоторой гибкости для интерфейсов с поддержкой не const.

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