Констанстный указатель на константу?

Что-то я запутался(

void Ge(wchar_t* buffer, size_t size) {

  wchar_t const* const message = L"Test Message!"; 
  std::cout << typeid(message).name() << std::endl;
  std::cout << "b: " << (const void*)message << std::endl;

wcscpy_s(buffer, size, message); 

}

wchar_t const* const message - широкосимвольный константный указатель на константу ? Или это указатель на константный объект типа whar_t?

Очень похоже на пример, ниже, когда не только само значение указателя является константой, но сам указатель не может менять свой адрес в памяти, т.к.

void print(const int* const x)  // константный указатель на константу
{
    int z{2};
    //x = &z; // значение указателя нельзя изменить
    std::cout << "z = " << z << std::endl;      // z = 2
    std::cout << "*x = " << *x << std::endl;    // *x = 10
}

Правильней будет сказать что это константный указатель который не может менять свой адрес в памяти и по этому адресу лежит константное значения типа wchar_t? Подскажите)


Ответы (3 шт):

Автор решения: Stanislav Volodarskiy

Неизменный указатель (сам адрес не меняется) на память без возможности писать (данные в памяти не меняются):

//                 указатель message никогда не будет
//                 указывать в другое место
//                 -------------
    wchar_t const* const message
//  -------------
//  указатель нельзя использовать
//  для изменения значений в памяти
//  `wchar_t const` и `const wchar_t` взаимозаменяемы

P.S. Объявление параметра константным в прототипе функции не меняет прототип:

void print(const int* const x)  // эти два прототипа 
void print(const int* x)        // ничем не отличаются

Поэтому при объявлении функции хороший тон не указывать const, а реализации вы вольны его использовать:

void print(const int* x);         // в объявлении const не пишут

...
 
void print(const int* const x) {  // в реализации можно писать
   // ...
}
→ Ссылка
Автор решения: HolyBlackCat

Все что до первой */(/... или до имени переменной (смотря что встречается первым) может быть в любом порядке.

const int x = 42; = int const x = 42;

const int *const x = int const *const x

Очень похоже на пример, ниже, когда не только само значение указателя является константой, но сам указатель не может менять свой адрес в памяти

Да, это оно и есть.


Еще, обратите внимание что typeid отбрасывает константность, так что для wchar_t const* const он выведет wchar_t const* (отбрасывается только константность самого указателя, а не того, на что он показывает).

Вместо этого есть такой трюк:

template <typename T>
void PrintType()
{
    std::cout <<
    #ifdef _MSC_VER
    __FUNCSIG__
    #else
    __PRETTY_FUNCTION__
    #endif
    << '\n';
}

А потом PrintType<decltype(message)>();. Это выводит настоящий тип.

→ Ссылка
Автор решения: Intelligent Shade of Blue

Есть очень простое правило:

const всегда относится к вещи левее него

Таким образом:

char const * foo = &v1; // изменяемый указатель на постоянное значение;
foo = &v2; // OK           указатель можно перенаправить, но значение куда
*foo = 'x'; // ERROR       он указывает нельзя изменить
char * const bar = &v1; // постоянный указатель на изменяемое значение;
bar = &v2; // ERROR        его нельзя перенаправить после инициализации,
*bar = 'x'; // OK          но через него можно изменить значение
char const * const baz = &v1; // постоянный указатель на постоянное значение
baz = &v2; // ERROR              нельзя перенаправить
*baz = 'x'; // ERROR             и нельзя изменить значение

У этого правила есть одно исключение:

Если const находится первым, то он относится к вещи правее него

То есть:

const char * qux; // эквивалентно выражению `char const * foo`

Демонстрация: godbolt

→ Ссылка