константная функция c ++, которая возвращает указатель const. Но какой тип const является возвращаемым указателем? - PullRequest
35 голосов
/ 08 октября 2010

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

Это так:

  1. int *const func() const
  2. const int* func() const
  3. 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;

Ответы [ 5 ]

66 голосов
/ 08 октября 2010

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

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

1. int * const func () const

Функция является константой, и возвращаемый указатель является константой, но «мусор внутри» может быть изменен. Однако я не вижу смысла возвращать константный указатель, потому что конечный вызов функции будет rvalue, а rvalues ​​не-классового типа не может быть const, что означает, что const будет игнорироваться в любом случае

2. const int* func () const

Это полезная вещь. «Хлам внутри» не может быть изменен

3. const int * const func() const

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

НТН

14 голосов
/ 08 октября 2010

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

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

void myFunction (const int value);

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

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

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

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

void myFunction (const MyClass &value);

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

void myFunction (const MyClass *value);

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

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

void myFunction (MyClass * const value);

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

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

const double squareRoot(double d);

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

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

const Customer *getCustomer(char *name);

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

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

const Customer *getCustomer(const char *name);
6 голосов
/ 08 октября 2010

int *const func() const

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

  • Взяв адрес func.
  • В C ++ 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

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

1 голос
/ 08 октября 2010

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

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

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

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

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

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

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

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

0 голосов
/ 08 октября 2010

Метод 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's value
        return p; 
    }
    int* const& get_reference_to_pointer() const //can't return a reference to non-const pointer
    {
        return p;
    }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...