C ++: странное поведение элемента данных указателя в контексте const - PullRequest
2 голосов
/ 16 октября 2011

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

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

#include <cstdio>
#include <cstdlib>
#include <cstring>

class Cat
{
public:
        Cat(char const *name)
        : _name(strdup(name))
        { }
        ~Cat(){ free(_name); }
        void SetName(char const *name)
        {
                free(_name);
                _name = strdup(name);
        }
        char const* GetName() const
        {
                _name[0] = 'P';
                return _name;
        }
private:
        char *_name;
};

int main()
{
        Cat c("lost+found");
        c.SetName("Molly");
        printf("%s\n",c.GetName());
        return 0;
}

Компиляция прошла без предупреждений и ошибок с помощью следующей команды:

g++ -W -Wall -Wextra -pedantic -Os pmc.cpp -o pmc

Вывод полученной программы составил Polly.

ОБНОВЛЕНИЕ Использование педантичного char const * вместо традиционного const char *

Ответы [ 3 ]

5 голосов
/ 16 октября 2011

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

Вы хотите что-то вроде std :: string здесь, то есть дополнительную семантику для указателя - например,гарантировать, что его содержание не изменится за пределами вашего класса.

3 голосов
/ 16 октября 2011

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

Вы ошибочно воспринимаете назначение квалификатора const.Он служит трем целям:

  • Константный экземпляр некоторого класса может вызывать только константные функции-члены этого класса.Вызовы функций-членов, которые не являются const-квалифицированными, запрещены в случае const-квалифицированного экземпляра.
  • Функция-const-квалифицированная функция-член не может изменить содержимое direct экземпляра.Содержимое, которое указывает на данные, внешние по отношению к экземпляру, не является частью прямого содержимого экземпляра;они просто не защищены квалификатором const.
  • Компилятору доступны огромные возможности для оптимизации на основе вышеприведенного.

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

2 голосов
/ 16 октября 2011

В функции-члене const тип _name становится char * const, что означает, что это константный указатель, а не данные, на которые указывает указатель.

Кажется, вы думаете, что _name становится const char*. Нет, const применяется к pointer, а не к данным, на которые он указывает. Так что _name должно стать char * const.

Чтобы свести к минимуму эту путаницу, я предпочитаю синтаксис T const вместо const T, хотя оба они в точности совпадают. Потому что если T равно char*, то T const станет char * const, тогда как const T станет const char*. В то время как первое помогает понять, второе усложняет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...