typedef

Proszę wziąć pod uwagę następujący kod:

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

const PersonRef person = NULL;

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

Z jakiegoś powodu kompilator skarży się, że nie można przypisać wartości tylko do odczytu. Ale słowo kluczowe const nie powinno powodować, że wskaźnik będzie const. Jakieś pomysły?

Author: Patryk, 2011-12-14

6 answers

Zauważ, że

typedef int* intptr;
const intptr x;

To nie to samo co:

const int* x;

intptr jest pointer do int. const intptr jest stałym wskaźnikiem do int, a nie wskaźnikiem do stałej int.

Więc po wskaźniku typedef, nie mogę już dostosować go do treści?

Są pewne brzydkie sposoby, takie jak typ makra gcc :

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

Ale, jak widzisz, to bez sensu, jeśli znasz typ za intptr.

 41
Author: Piotr Praszmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-27 07:09:56
const PersonRef person = NULL;

Jest

struct Person*const person= NULL;

Więc konstruujesz wskaźnik, a nie obiekt.

 7
Author: Jens Gustedt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-14 12:32:22

Chociaż problem jest już rozwiązany przez odpowiedzi powyżej, brakuje mi powodu...

Więc może z reguły:

  1. const zawsze odnosi się do swojego poprzednika.
  2. w przypadku, gdy nie ma takiego, to" konstruuje " zamiast tego token następcy.

Ta zasada może naprawdę pomóc w deklarowaniu wskaźnika do wskaźników const lub czegoś równie schludnego.

W każdym razie, mając to na uwadze, powinno być jasne dlaczego

struct Person *const person = NULL;

Deklaruje wskaźnik const do zmiennej struktury.

Pomyśl o tym, Twój typedef "grupy" struct Person z tokenem wskaźnika *. Do pisania

const PersonRef person = NULL;

Twój kompilator widzi coś takiego (pseudo-kod):

const [struct Person *]person = NULL;

Ponieważ nie ma nic do const's lewo, to deklaruje token do to jest prawo struct Person * stała.

Cóż, myślę, że to jest powód, dla którego nie lubię ukrywania wskaźników przez typedefs, podczas gdy Lubię typedefs jako takie. Co z pisaniem

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

I powinno być jasne dla kompilatorów i ludzi, co robisz.

 6
Author: Zappotek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-14 13:50:19

Nigdy nie ukrywaj wskaźników za typedefami, jest to naprawdę zła praktyka i tworzy tylko błędy.

Jednym z takich niesławnych błędów jest to, że typ wskaźnika typedef:ed zadeklarowany jako const będzie traktowany jako "stały wskaźnik do stałych danych", a nie "stały wskaźnik do stałych danych", czego intuicyjnie się oczekuje. To właśnie dzieje się w twoim programie.


Rozwiązanie:

typedef struct
{
  int age;
} Person;

const Person* person = NULL; // non-constant pointer to constant Person
 2
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-14 13:43:10

Dostajesz i błąd

error: assignment of read-only variable ‘person’

On statement

person = newPerson;

Ponieważ zadeklarowałeś osobę jako const, więc jej wartość jest tylko do odczytu .... wartość const nie może być zmieniona

Jeśli zamierzasz to zmienić, to po co to robisz?

Usuń słowo kluczowe const Twój kod będzie działał dobrze

 0
Author: Jeegar Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-14 12:34:58

Jako uzupełnienie (zaakceptowanej) odpowiedzi Piotra, można uniknąć GCC-specific 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");

Zmieniając foo_t<T> na foo<T>::type powyżej i / lub używając wersji boost ' a, można to zrobić nawet w C++98, chociaż jest to tylko ładne od C++11.


Alternatywnie, użyj dwóch różnych typów, które działają również dla przypadków innych niż zwykłe wskaźniki. Na przykład, rozważmy typy kontenerów iterator i const_iterator.

 0
Author: o11c,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-14 04:31:21