указатель на typedef - PullRequest
       34

указатель на typedef

21 голосов
/ 14 декабря 2011

пожалуйста, рассмотрите следующий код:

typedef struct Person* PersonRef;
struct Person {
  int age;
};

const PersonRef person = NULL;

void changePerson(PersonRef newPerson) {
  person = newPerson;
}

По какой-то причине компилятор жалуется на значение, доступное только для чтения, которое нельзя назначить.Но ключевое слово const не должно делать указатель постоянным.Есть идеи?

Ответы [ 6 ]

41 голосов
/ 14 декабря 2011

Обратите внимание, что

typedef int* intptr;
const intptr x;

- это не то же самое, что:

const int* x;

intptr - указатель на int.const intptr - это постоянный указатель на int, а не указатель на постоянную int.

, поэтому после указателя typedef я больше не могу сделать его константой содержимому?

Есть несколько уродливых способов, таких как макрос typeof * gcc :

typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;

, но, как вы видите, бессмысленно, если вы знаете тип intptr.

7 голосов
/ 14 декабря 2011
const PersonRef person = NULL;

равно

struct Person*const person= NULL;

, поэтому вы используете указатель, а не объект.

6 голосов
/ 14 декабря 2011

Хотя проблема уже решена ответами выше, я скучаю по причине, почему ...

Так, может быть, как правило:

  1. const всегда ссылается на маркер своего предшественника.
  2. В случае, если такого не существует, вместо этого он "создает" свой токен-преемник.

Это правило действительно может помочь вам объявить указатель на константные указатели или что-то такое же аккуратное.

В любом случае, имея это в виду, должно быть понятно, почему

struct Person *const person = NULL;

объявляет константный указатель на изменчивую структуру.

Подумайте об этом, ваш typedef "группы" struct Person с маркером указателя *. Итак, для написания

const PersonRef person = NULL;

ваш компилятор видит что-то подобное (псевдокод):

const [struct Person *]person = NULL;

Так как слева от const ничего нет, он декларирует токен вправо struct Person * константа.

Ну, я думаю, это причина, почему я не люблю скрывать указатели с помощью typedefs, а мне нравятся typedefs как таковые. Как насчет письма

typedef struct Person { ... } Person;
const Person *person; /*< const person */
Person *const pointer; /*< const pointer to mutable person */

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

2 голосов
/ 14 декабря 2011

Никогда не скрывайте указатели за typedefs, это действительно очень плохая практика, и она только создает ошибки.

Одна из таких печально известных ошибок заключается в том, что тип указателя typedef: ed, объявленный как const, будет обрабатываться как «постоянный указатель на непостоянные данные», а не как «непостоянный указатель на постоянные данные»это то, что интуитивно ожидает.Вот что происходит в вашей программе.


Решение:

typedef struct
{
  int age;
} Person;

const Person* person = NULL; // non-constant pointer to constant Person
0 голосов
/ 14 мая 2018

В качестве дополнения к (принятому) ответу Петра можно избежать специфичных для GCC typeof:

static_assert(std::is_same<const int *, std::add_const_t<std::remove_pointer_t<intptr>> *>::value, "not same via type_traits");
static_assert(std::is_same<const int *, std::remove_reference_t<decltype(std::as_const(*intptr()))>*>::value, "not same via decltype");

, изменив foo_t<T> на foo<T>::type выше и / или используя версию boostэто даже возможно сделать в C ++ 98, хотя это довольно красиво, начиная с C ++ 11.


В качестве альтернативы, используйте два разных typedef, что также работает для случаев, отличных от простых указателей.Например, рассмотрим каждый тип iterator и const_iterator typedefs.

0 голосов
/ 14 декабря 2011

вы получаете и ошибка

error: assignment of read-only variable ‘person’

в заявлении

person = newPerson;

потому что вы объявили person как const, поэтому его значение доступно только для чтения .... значение const не может быть изменено

Если вы собираетесь изменить это жизнеспособное состояние, тогда почему вы его используете?

удалить ключевое слово const, ваш код будет работать нормально

...