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

С++ const member function, которая возвращает указатель const. Но какой тип const является возвращаемым указателем?

Я прошу прощения, если это было задано, но как создать функцию-член в С++, которая возвращает указатель в следующих сценариях: 1. Возвращаемый указатель является постоянным, но мусор внутри может быть изменен. 2. Хранение внутри является постоянным, но возвращаемый указатель может быть изменен. 3. Ни мусор, ни указатель не могут быть изменены.

Это так:

  • int *const func() const
  • const int* func() const
  • const int * const func() const

Все обучающие материалы, которые я прочитал, не охватывают это различие.

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

а. void func(const int* const x) const;
б. void func(const int* x) const;
с. void func(const int* const x) const;

4b9b3361

Ответ 1

Я не знаю, какую книгу вы прочитали, но если вы отметите метод const, это означает, что this будет иметь тип const MyClass* вместо MyClass*, что, в свою очередь, означает, что вы не можете изменять нестатические члены данных, которые не объявлены mutable, и вы не можете вызывать любые неконстантные методы на this.

Теперь для возвращаемого значения.

1. int * const func () const

Функция постоянна, и возвращаемый указатель является постоянным, но "мусор внутри" может быть изменен. Тем не менее, я не вижу смысла возвращать указатель const, потому что окончательный вызов функции будет rvalue, а значения типа non-class не могут быть const, а это означает, что const будет проигнорирован в любом случае

2. const int* func () const

Это полезная вещь. Невозможно изменить "мусор внутрь"

3. const int * const func() const

семантически почти то же, что и 2, из-за причин в 1.

НТН

Ответ 2

Некоторые использования const не имеют особого смысла.

Предположим, что у вас есть следующая функция:

void myFunction (const int value);

Константа сообщает компилятору, что значение не должно меняться внутри функции. Эта информация не имеет значения для вызывающего абонента. Это зависит от самой функции, чтобы решить, что делать со значением. Для вызывающего лица для него следующие два определения функций ведут себя одинаково:

void myFunction (const int value);
void myFunction (int value);

Поскольку значение передается по значению, это означает, что функция все равно получает локальную копию.

С другой стороны, если аргумент является ссылкой или указателем, все становится совсем другим.

void myFunction (const MyClass &value);

Это говорит вызывающему, что значение передается по ссылке (поэтому позади экранов оно фактически является указателем), но вызывающий promises не изменяет значение. То же самое верно для указателей:

void myFunction (const MyClass *value);

Мы передаем указатель на MyClass (из-за причин производительности), но функция promises не меняет значение.

Если мы напишем следующее:

void myFunction (MyClass * const value);

Тогда мы вернемся к первой ситуации. myFunction получает указатель, который передается по значению, и который является константой. Поскольку MyFunction получает копию значения указателя, для вызывающего не имеет значения, является ли оно const или нет. Самое главное, что myFunction может изменять содержимое значения, потому что сама переменная-указатель является константой, но содержимое в ней отсутствует.

То же самое верно для возвращаемых значений:

const double squareRoot(double d);

Это не имеет никакого смысла. squareRoot возвращает double, но поскольку он передается "по значению" и поэтому его нужно скопировать в мою локальную переменную, я могу делать все, что захочу.

С другой стороны:

const Customer *getCustomer(char *name);

Сообщает мне, что getCustomer возвращает мне указатель на клиента, и мне не разрешают изменять содержимое клиента.

Собственно, было бы лучше сделать содержимое char -pointer-content const, так как я не ожидаю, что функция изменит данную строку:

const Customer *getCustomer(const char *name);

Ответ 3

int *const func() const

Вы не можете наблюдать const здесь, за исключением нескольких случаев

  • Принимая адрес func.
  • В С++ 0x прямой вызов func с синтаксисом функции-вызова в качестве операнда decltype даст int * const.

Это происходит потому, что вы возвращаете значение чистого указателя, то есть значение указателя, которое фактически не хранится в переменной указателя. Такие значения не являются константными, потому что они не могут быть изменены в любом случае. Вы не можете сказать obj.func() = NULL;, даже если вы уберете const. В обоих случаях выражение obj.func() имеет тип int* и не модифицируется (кто-то скоро укажет стандарт и придумает термин "rvalue" ).

Итак, в контекстах вы используете возвращаемое значение, которое вы не сможете определить разницу. Только в случаях, когда вы ссылаетесь на декларацию или на целую функцию, вы заметите разницу.

const int* func() const

Это то, что вы обычно делали бы, если бы тело было чем-то вроде return &this->intmember;. Это не позволяет изменять int-член, выполняя *obj.func() = 42;.

const int * const func() const

Это только комбинация первых двух:)

Ответ 4

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

Это потому, что возвращаемое значение принадлежит вызывающей функции, т.е. это их собственная копия, поэтому не имеет значения, изменяют ли они ее (указывая на что-то еще). Однако контент не "принадлежит" вызывающему абоненту, и разработчик функции может заключить контракт, что он доступен только для чтения.

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

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

  • Мьютексы, которые вы хотите заблокировать даже для чтения.
  • Данные, которые загружаются с лени, т.е. заполняются при первом доступе.
  • Объекты с подсчетом ссылок: вы хотите увеличить счетчик ссылок, если у него есть другой просмотрщик, поэтому вы изменяете его состояние только для его чтения.

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

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

  • Если вы хотите, в частности, вызвать перегрузку const, но иметь неконстантную ссылку. Сначала переведите его в const.

Ответ 5

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

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

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

Пример:

class X
{
    int* p;
public:
    int* get_copy_of_pointer() const //the returned value is a copy of this->p
    { 
        *p = 42;  //this being const doesn't mean that you can't modify the pointee
        //p = 0;  //it means you can't modify the pointer value
        return p; 
    }
    int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer
    {
        return p;
    }
};