Який сенс указівників const?


149

Я кажу не про покажчики на значення const, а про самі const покажчики.

Я вивчаю C та C ++ за межами самого елементарного матеріалу, і лише до сьогодні я зрозумів, що покажчики передаються за значенням функції, що має сенс. Це означає, що всередині функції я можу зробити скопійований покажчик вказувати на якесь інше значення, не впливаючи на вихідний покажчик від абонента.

Тож який сенс мати заголовок функції, який говорить:

void foo(int* const ptr);

Всередині такої функції ви не можете зробити ptr вказівкою на щось інше, тому що це const, і ви не хочете, щоб воно було змінене, а така функція:

void foo(int* ptr);

Робота так само добре! тому що вказівник скопіюється в будь-якому випадку, і вказівник у виклику не впливає, навіть якщо ви модифікуєте копію. То в чому перевага const?


29
Що робити, якщо ви хочете гарантувати під час компіляції, що покажчик не може і не повинен бути змінений, щоб вказувати на щось інше?
Platinum Azure

25
Точно така ж точка, як і будь-який constпараметр.
Девід Геффернан

2
@PlatinumAzure, я маю декілька років досвіду програмування, але моєї програмної практики не вистачає. Я радий, що я поставив це питання, тому що ніколи не відчував необхідності робити компілятор вказувати на власні логічні помилки. Моя початкова реакція в той момент, коли я подав запитання, був: "чому я повинен дбати, якщо покажчик буде змінено? Це не вплине на абонента". Поки я не прочитав усі відповіді, я зрозумів, що мені слід піклуватися, тому що якщо я спробую змінити його, я і моя логіка кодування помиляються (або була помилка друку, як пропущена зірочка), і я, можливо, не зрозумів, якби компілятор не став ' не кажи мені.
Р. Руїз.

3
@ R.Ruiz. Без сумніву, навіть найдосвідченіший з нас міг би зробити додаткові гарантії правильності. Оскільки інженерія програмного забезпечення - це форма інженерії, де може бути прийнятним трохи більше простору (випадкові HTTP 502, повільні з'єднання; випадкові зображення, які не завантажуються, не є надзвичайними випадками, але несправність двигуна в літаку є неприйнятною і, ймовірно, серйозною), іноді люди програмують із зайвою поспішністю. Цей же аргумент, який виправдовує написання одиничних тестів, пояснить використання constгарантій на правильність. Це просто змушує нас відчувати себе більш впевненими, що наш код непереборно правильний.
Platinum Azure

3
Пов'язаний з цим питання: stackoverflow.com/questions/219914 / ...
Raedwald

Відповіді:


207

const це інструмент, який ви повинні використовувати для виконання дуже важливої ​​концепції C ++:

Знайдіть помилки під час компіляції, а не під час виконання, отримавши компілятор для виконання того, що ви маєте на увазі.

Навіть незважаючи на те, що це не змінює функціональність, додавання constстворює помилку компілятора, коли ви робите те, чого не хотіли робити. Уявіть собі наступний друк:

void foo(int* ptr)
{
    ptr = 0;// oops, I meant *ptr = 0
}

Якщо ви використовуєте int* const, це призведе до помилки компілятора, оскільки ви змінюєте значення на ptr. Додавання обмежень за допомогою синтаксису - це взагалі гарна річ. Просто не забирайте це занадто далеко - приклад, який ви подали, - це випадок, коли більшість людей не намагаються використовувати const.


8
Дякую, це відповідь, яка мене переконує. Ви ставите const, щоб компілятор попередив вас про ваші власні помилки у призначенні. Ваш приклад прекрасно проілюструє цю концепцію, оскільки це звичайна помилка вказівників. Ніж ви!
Р. Руїз.

25
"Допоможіть компілятору допомогти вам" - це мантра, яку я зазвичай співаю на це.
Flexo

1
+1, але ось цікавий випадок , коли це argueable: stackoverflow.com/questions/6305906 / ...
Raedwald

3
тож це та сама відповідь, яку ви давали б "Чому робити змінні приватними, коли їх просто не можна використовувати поза класом".
Лі Лув’є

це може бути трохи поза темою, але де цей покажчик const сидить у пам'яті? Я знаю, що всі const сидять у глобальній частині пам’яті, але я не впевнений на 100% у тому, що const, який ти передаєш як функціональний вар. спасибі і вибачте, якщо це поза темою
Томер

77

Я зазначаю, що використовую лише const аргументи, тому що це дозволяє більше перевіряти компілятор: якщо я випадково повторно призначу значення аргументу всередині функції, компілятор мене кусає.

Я рідко використовую змінні, то чистіше створювати нові змінні для зберігання нових значень, тому, по суті, всі мої декларації змінних є const(за винятком деяких випадків, таких як змінні циклу, де constзаважає код працювати).

Зауважте, що це має сенс лише у визначенні функції. Він не належить до декларації , що бачить користувач. І користувачеві все одно, чи я використовую constпараметри всередині функції.

Приклад:

// foo.h
int frob(int x);
// foo.cpp
int frob(int const x) {
   MyConfigType const config = get_the_config();
   return x * config.scaling;
}

Зауважте, як аргумент, так і локальна змінна const. Ні це не потрібно, але функції, які ще трохи більше, це не раз врятувало мене від помилок.


17
+1з іншого - constодержимий фанатик. Однак я вважаю за краще мої компілятори гавкати на мене. Я роблю занадто багато помилок і страждаю, щоб сильно покусати.
sbi

2
+1, я настійно рекомендую constстратегію " якщо немає вагомих причин". Однак є кілька хороших винятків, наприклад, Copy and swap
Flexo

2
Якби я розробляв нову мову, за замовчуванням оголошені об'єкти були б лише для читання ("const"). Вам потрібен спеціальний синтаксис, можливо ключове слово "var", щоб зробити об'єкт доступним для запису.
Кіт Томпсон

@Keith Я спокусився сказати "звичайно". Все інше в цьому моменті нерозумно. Але, на жаль, більшість мовних дизайнерів, здається, не погоджуються з нами ... Насправді я вже стільки ж розмістив (у видаленому запитанні "Яка ваша найсуперечливіша думка щодо програмування?").
Конрад Рудольф

1
@KubaOber Я не бачу, як це взагалі песимізація. Якщо пізніше ви виявите, що вам потрібно змінити те, що було передано в тілі функції, то просто відкиньте constаргумент і бажано прокоментуйте чому. Ця крихітна додаткова робота не виправдовує те, що усі аргументи не constза замовчуванням і відкриття себе перед усіма можливими помилками.
підкреслюй_

20

Ваше питання стосується чогось більш загального: чи повинні аргументи функцій бути const?

Константність аргументів значення (як ваш покажчик) - це деталь реалізації , і вона не є частиною декларації функції. Це означає, що ваша функція завжди така:

void foo(T);

Це повністю залежить від реалізатора функції, чи хоче вона використовувати змінну аргумента функції-область в змінному або постійному вигляді:

// implementation 1
void foo(T const x)
{
  // I won't touch x
  T y = x;
  // ...
}

// implementation 2
void foo(T x)
{
  // l33t coding skillz
  while (*x-- = zap()) { /* ... */ }
}

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


5
Я погоджуюся з цим - але мені дещо незручно з ідеєю зробити декларацію та визначення різними. Для речей, окрім constдекларації та (прототипної частини) визначення, як правило, ідентичні.
Кіт Томпсон

@KeithThompson: Ну, не потрібно робити цього, якщо цього не хочеш. Просто не вкладайте constв декларацію. Це повністю залежить від вас, якщо ви хочете додати кваліфікаційний елемент у реалізації.
Керрек СБ

1
Як я вже сказав, я погоджуюся, що ставити constдекларацію, але не визначення має сенс. Це просто відчуває проблему в мові, що це єдиний випадок, коли декларація та визначення не є тотожними має сенс. (Це, навряд чи, єдиний глюк C, звичайно.)
Кіт Томпсон,

16

Класифікатор вищого рівня const відкидається в деклараціях, тому декларації у питанні декларують точно таку ж функцію. З іншого боку, у визначенні (реалізації) компілятор перевірить, що якщо ви позначаєте вказівник як const, він не змінюється всередині тіла функції.


Я цього не знав. Отже, якщо я спробую перевантажити void foo (int * const ptr) void foo (int * t ptr), я отримаю помилку компілятора. Дякую!
Р. Руїз.

@ R.Ruiz. Якщо ваше уповільнення є void foo (int * t ptr), а ваше визначення - void foo (int * const ptr), ви НЕ отримаєте помилку компілятора.
Тревор Хікі

1
@TrevorHickey Вони будуть ... але не з тієї причини, яку вони думають. int* t ptr- синтаксична помилка. Без цього вони однакові для перевантажувальних цілей.
підкреслюй_

14

Ви маєте рацію, для абонента це абсолютно не має значення. Але для письменника функції це може бути мережею безпеки "гаразд, мені потрібно переконатися, що я не вказую на те, що я неправильно". Не дуже корисний, але і не марний.

Це в основному те саме, що мати int const the_answer = 42у своїй програмі.


1
Що має значення, де вони вказують, це вказівник, виділений на стек? Функція не може це зіпсувати. Куди більше сенсу використовувати покажчики, які доступні лише для читання, при роботі із вказівниками. Це не те саме, що int const! Я спростую це лише за оманливе твердження. const intі int constє рівнозначними, хоча const int*і int* constмають два різних значення!
Лундін

1
@lundin Припустимо, що функція велика і в ній є інші речі. Випадково хтось може вказати на щось інше (на стек функції). Це не проблематично для абонента, але, безумовно, може бути для абонента. У своїх твердженнях я не бачу нічого оманливого: " для виконавця функції це може бути мережею безпеки".
cnicutar

1
@Lundin Про int constчастину; Я кладу тип перед const (це звучить неприродно) протягом деякого часу, і я знаю про відмінності. Ця стаття може виявитися корисною. Однак у мене були трохи інші причини перейти на цей стиль.
cnicutar

1
Добре. Я щойно написав свою власну відповідь на випадок, якщо хтось ще, окрім вас і мене, читає цю публікацію. Я також включив обґрунтування того, чому int const - це поганий стиль, а const int - хороший стиль.
Лундін

Лундін, я теж читаю! Я згоден, що const int є кращим стилем. @cnicutar, ваша перша відповідь на Лундіна - це те, що я шукав, коли я подав це запитання. Тож проблема полягає не в телефоні (як я бездумно думав), але const - це гарантія для виклику. Мені подобається ця ідея, дякую.
Р. Руїз.

14

До constключового слова дуже багато , воно досить складне. Як правило, додавання великої кількості const вашій програмі вважається хорошою практикою програмування, шукайте в Інтернеті "правильність const", і ви знайдете багато інформації про це.

Ключове слово const - це так званий "кваліфікаційний тип", інші - volatileі restrict. Принаймні мінливі слідують тим же (заплутаним) правилам, що і const.


Перш за все, ключове слово const служить двом цілям. Найбільш очевидним є захист даних (та покажчиків) від навмисного чи випадкового неправомірного використання, роблячи їх лише для читання. Будь-яка спроба змінити змінну const буде помічена компілятором під час компіляції.

Але в будь-якій системі з пам'яттю лише для читання є ще одна мета, а саме - забезпечити виділення певної змінної всередині такої пам’яті - це може бути, наприклад, EEPROM або спалах. Вони відомі як енергонезалежні спогади, NVM. Змінна, виділена в NVM, як і раніше, звичайно, буде дотримуватися всіх правил змінної const.

Існує кілька різних способів використання constключового слова:

Оголосити постійну змінну.

Це можна зробити як

const int X=1; or
int const X=1;

Ці дві форми абсолютно рівнозначні . Останній стиль вважається поганим стилем і його не слід використовувати.

Причина, чому другий ряд вважається поганим стилем, ймовірно, тому, що "специфікатори класу зберігання", такі як статичні та зовнішні, також можуть бути оголошені після фактичного типу int staticтощо. Але це робиться для специфікаторів класу зберігання, позначається як застаріла функція комітетом C (проект ISO 9899 N1539, 6.11.5). Тому для послідовності також не слід писати класифікаторів типу таким чином. Це не має жодної іншої мети, окрім як би заплутати читача.

Оголосити вказівник на постійну змінну.

const int* ptr = &X;

Це означає, що вміст "X" неможливо змінити. Це звичайний спосіб декларування вказівників подібним чином, головним чином як частина параметрів функції для "правильності const". Оскільки "X" насправді не потрібно оголошувати як const, це може бути будь-яка змінна. Іншими словами, ви завжди можете "оновити" змінну до const. Технічно C також дозволяє переходити з const до простої змінної за допомогою явних типових передач, але це вважається поганим програмуванням, і компілятори зазвичай дають застереження проти цього.

Оголосити постійним вказівником

int* const ptr = &X;

Це означає , що покажчик сам є постійним. Ви можете змінювати, на що він вказує, але ви не можете змінювати сам покажчик. Це не має багатьох застосувань, є кілька таких, як забезпечення того, що вказівник (вказівник на вказівник) не змінює свою адресу під час передачі як параметр функції. Вам доведеться написати щось не надто читабельне, як це:

void func (int*const* ptrptr)

Я сумніваюся, що багато програмістів на C можуть отримати const та * прямо там. Я знаю, що не можу - мені довелося перевірити GCC. Я думаю, що тому ви рідко коли-небудь бачите цей синтаксис для вказівника на вказівник, навіть якщо це вважається хорошою практикою програмування.

Постійні покажчики також можуть бути використані для того, щоб сама змінна вказівника була оголошена в пам'яті лише для читання, наприклад, ви могли б захотіти оголосити якусь таблицю пошуку на основі вказівника та розподілити її в NVM.

І звичайно, як вказують інші відповіді, постійні покажчики також можуть бути використані для забезпечення "правильності const".

Оголосити постійний вказівник на постійні дані

const int* const ptr=&X;

Це два типи вказівників, описані вище, у поєднанні, з усіма атрибутами обох.

Оголосити функцію члена лише для читання (C ++)

Оскільки це позначено C ++, я також повинен зазначити, що ви можете оголосити функції члена класу як const. Це означає, що функції заборонено змінювати жодного іншого члена класу при його виклику, що і запобігає програмісту класу від випадкових помилок, але й інформує абонента функції-члена, що вони нічого не будуть збивати вгору, зателефонувавши до цього. Синтаксис:

void MyClass::func (void) const;

8

... сьогодні я зрозумів, що покажчики передаються за значенням функції, що має сенс.

(imo) це насправді не має сенсу як за замовчуванням. більш розумним за замовчуванням є передача як непризначний покажчик ( int* const arg). тобто я вважав за краще, щоб покажчики передавались, оскільки аргументи неявно оголошувались const.

То в чому перевага const?

Перевага полягає в тому, що це досить просто і іноді незрозуміло, коли ви змінюєте адресу, на яку вказує аргумент, так що ви можете ввести помилку, коли це не const досить легко. зміна адреси нетипова. чіткіше створити локальну змінну, якщо ваш намір змінити адресу. а також, маніпуляція з необробленими покажчиками - це простий спосіб ввести помилки.

тому чіткіше пройти за незмінною адресою та створити копію (у тих нетипових випадках), коли ви хочете змінити адресу, на яку вказує аргумент:

void func(int* const arg) {
    int* a(arg);
    ...
    *a++ = value;
}

додаючи, що локальна програма практично безкоштовна, і це зменшує ймовірність помилок, одночасно покращуючи читабельність.

на більш високому рівні: якщо ви маніпулюєте аргументом як масив, клієнт, як правило, ясніше і менше помилок схильний оголошувати аргумент як контейнер / колекцію.

загалом, додавання const до значень, аргументів та адрес є гарною ідеєю, оскільки ви не завжди усвідомлюєте побічні ефекти, які компілятор із задоволенням застосовує. Отже, він настільки ж корисний, як const, як і в інших кількох випадках (наприклад, питання схоже на "Чому я повинен оголошувати значення const?"). на щастя, у нас також є посилання, які неможливо перепризначити.


4
+1 - це за замовчуванням. C ++, як і більшість мов, має неправильний шлях. Замість того, щоб мати constключове слово, воно повинно мати mutableключове слово (ну, воно є, але з неправильною семантикою).
Конрад Рудольф

2
Цікава ідея з const як за замовчуванням. Дякую за вашу відповідь!
Р. Руїз.

6

Якщо ви робите вбудовані системи або програмування драйверів пристроїв, де у вас є пристрої з картографічною пам'яттю, то обидві форми 'const' часто використовуються, одна для запобігання переназначенню вказівника (оскільки він вказує на фіксовану апаратну адресу.) І, якщо периферійний Реєстрація, на яку він вказує, - це регістр апаратного забезпечення лише для читання, тоді інший const виявить багато помилок під час компіляції, а не під час виконання.

16-бітний периферійний регістр мікросхеми може виглядати приблизно так:

static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;

Тоді ви можете легко прочитати реєстр апаратних засобів, не вдаючись до мови складання:

input_word = *peripheral;


5

int iVal = 10; int * const ipPtr = & iVal;

Подібно до звичайної змінної const, покажчик const повинен бути ініціалізований до значення після оголошення, і його значення не може бути змінено.

Це означає, що вказівник const завжди вказуватиме на одне значення. У наведеному вище випадку ipPtr завжди вказуватиме на адресу iVal. Однак, оскільки значення, на яке вказується, все ще не є const, можна змінити значення, на яке вказували, шляхом перенаправлення покажчика:

* ipPtr = 6; // дозволено, оскільки pnPtr вказує на non-const int


5

Те саме питання можна задати стосовно будь-якого іншого типу (не лише вказівників):

/* Why is n const? */
const char *expand(const int n) {
    if (n == 1) return "one";
    if (n == 2) return "two";
    if (n == 3) return "three";
    return "many";
}

LOL, ти маєш рацію. Випадок покажчиків мені спочатку прийшов до тями, тому що я вважав, що вони особливі, але вони подібно до будь-якої іншої змінної, переданої за значенням.
Р. Руїз.

5

Ваше запитання справді більше про те, чому визначати будь-яку змінну як const, а не просто параметр const pointer до функції. Тут застосовуються ті самі правила, що і коли ви визначаєте будь-яку змінну як постійну, якщо її параметр функціонує або змінна члена або локальна змінна.

У вашому конкретному випадку функціонально це не має різниці, як у багатьох інших випадках, коли ви оголошуєте локальну змінну як const, але вона ставить обмеження, що ви не можете змінювати цю змінну.


ваш коментар дає зрозуміти, наскільки моє запитання марне, тому що ви праві: це те саме, що і будь-який інший параметр як const. Це може здатися марним, але саме там, щоб допомогти програмісту мати це обмеження і уникнути помилок
Р. Руїс.

4

Передача покажчика const на функцію має мало сенсу, оскільки вона буде передана за значенням у будь-якому випадку. Це просто одна з тих речей, які дозволяється загальним дизайном мови. Заборона цього лише тому, що це не має сенсу, просто зробить специфікацію мови. більший.

Якщо ви знаходитесь у функції, це, звичайно, інший випадок. Наявність покажчика, який не може змінити те, на що він вказує, - це твердження, яке робить код яснішим.


4

Я думаю, перевагою було б те, що компілятор може проводити більш агресивні оптимізації всередині функції, знаючи, що цей покажчик не може змінитися.

Це також уникає, наприклад. передаючи цей покажчик на підфункцію, яка приймає неконст-посилання вказівника (і, отже, може змінити вказівник на зразок void f(int *&p)), але я згоден, що корисність у цьому випадку дещо обмежена.


+1 для оптимізацій. Принаймні книги говорять, що це правда. Я хотів би зрозуміти, що саме таке оптимізація
Р. Руїс.

4

Приклад того, коли вказівник const дуже застосовний, може бути продемонстрований таким чином. Подумайте, що у вас є клас з динамічним масивом всередині нього, і ви хочете передати користувачеві доступ до масиву, але не надаючи їм прав на зміну вказівника. Поміркуйте:

#include <new>
#include <string.h>

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const GetArray(){ return Array; }
};

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
    Temp.GetArray()[1] = ' '; 
    printf("%s\n",Temp.GetArray());
}

Що виробляє:

Вхідні дані
ставлять дані

Але якщо ми спробуємо це:

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}

Ми отримуємо:

помилка: потрібне значення lvalue як лівий операнд присвоєння // Drat foiled again!

Так чітко ми можемо змінювати вміст масиву, але не вказівник масиву. Добре, якщо ви хочете переконатися, що покажчик має стійкий стан при передачі його назад користувачеві. Однак є один улов:

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    delete [] Temp.GetArray(); //Bwuahaha this actually works!
}

Ми все ще можемо видалити посилання пам'яті вказівника, навіть якщо ми не можемо змінити сам вказівник.

Отже, якщо ви хочете, щоб посилання на пам'ять завжди вказувало на щось (IE ніколи не змінюється, як це працює в даний час), то це дуже застосовно. Якщо ви хочете, щоб користувач мав повний доступ та модифікував його, тоді неконстація - це для вас.

Редагувати:

Зауваживши коментар okorz001 про неможливість призначити через те, що GetArray () є операндом правого значення, його коментар цілком правильний, але вищезазначене все-таки застосовується, якщо ви повинні повернути посилання на покажчик (я припускаю, що я припускав, що GetArray був посилаючись на посилання), наприклад:

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; } //Note & reference operator
        char * &GetNonConstArray(){ return Array; } //Note non-const
};

int main()
{
    TestA Temp;
    Temp.GetArray() = NULL; //Returns error
    Temp.GetNonConstArray() = NULL; //Returns no error
}

Повернеться в першій, що призведе до помилки:

помилка: призначення місцезнаходження лише для читання 'Temp.TestA :: GetArray ()'

Але друге відбудеться весело, незважаючи на потенційні наслідки внизу.

Очевидно, постане питання "чому ви хочете повернути посилання на покажчик"? Є рідкісні випадки, коли потрібно призначити пам'ять (або дані) безпосередньо оригінальному вказівнику, про який йдеться (наприклад, створення власного malloc / free або new / free front-end), але в цих випадках це посилання, що не стосується const . Посилання на const покажчик Я не натрапив на ситуацію, яка б його вимагала (хіба що, можливо, як оголошені змінні const-посилання, а не типи повернення?).

Подумайте, чи є у нас функція, яка бере покажчик const (проти тієї, яка не відповідає):

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; }

        void ModifyArrayConst(char * const Data)
        {
            Data[1]; //This is okay, this refers to Data[1]
            Data--; //Produces an error. Don't want to Decrement that.
            printf("Const: %c\n",Data[1]);
        }

        void ModifyArrayNonConst(char * Data)
        {
            Data--; //Argh noo what are you doing?!
            Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
            printf("NonConst: %c\n",Data[1]);
        }
};

int main()
{
    TestA Temp;
    Temp.ModifyArrayNonConst("ABCD");
    Temp.ModifyArrayConst("ABCD");
}

Помилка в const видає таким чином повідомлення:

помилка: зменшення параметра "Дані" лише для читання

Що добре, оскільки ми, мабуть, не хочемо цього робити, якщо тільки ми не хочемо викликати проблеми, зазначені в коментарях. Якщо ми редагуємо декремент у функції const, відбувається таке:

NonConst: A
Const: B

Зрозуміло, що навіть якщо A є "Дані [1]", це трактується як "Дані [0]", тому що покажчик NonConst дозволив операцію декременту. Як реалізується const, як пише інша людина, ми виявляємо потенційну помилку ще до її появи.

Ще одним головним моментом є те, що вказівник const може бути використаний як псевдопосилання, оскільки те, що опорні точки не можуть бути змінені (можна задатись питанням, чи можливо це було, як воно було реалізовано). Поміркуйте:

int main()
{
    int A = 10;
    int * const B = &A;
    *B = 20; //This is permitted
    printf("%d\n",A);
    B = NULL; //This produces an error
}

При спробі компіляції видається така помилка:

помилка: присвоєння змінної лише для читання "B"

Що, мабуть, погано, якщо потрібно було постійне посилання на А. Якщо B = NULLце буде прокоментовано, компілятор із задоволенням дозволить нам змінити, *Bі тому А. Це може здатися не корисним для ints, але врахуйте, якщо ви мали єдину позицію графічного додатку, де ви хотіли б не зміненого вказівника, який посилався на нього, що ви можете передати навколо.

Це використання є змінним (вибачте від ненавмисного каламбура), але правильно використовується, це ще один інструмент у вікні для допомоги у програмуванні.


2
Temp.GetArray() = NULLвиходить з ладу, тому що Temp.GetArray()є оцінкою, а не тому, що це кваліфіковано const. Крім того, я вважаю, що класифікатор const позбавлений усіх типів повернення.
Оскар Корц

@ okorz001: Після тестування ви справді правильні. Однак вищезазначене застосовується, якщо ви повернете посилання на сам покажчик. Я відповідно відредагую свою публікацію.
SSight3

3

У покажчиках немає нічого особливого, де ви ніколи не хочете, щоб вони були const. Так само, як ви можете мати постійні intзначення для члена класу , ви також можете мати постійні вказівники з подібних причин: Ви хочете переконатися, що ніхто ніколи не змінює те, на що вказується. Посилання C ++ дещо вирішують це, але поведінка вказівника успадковується від C.



3

Типи декларування будь-яких змінних на зразок
(1) Декларування постійної змінної.
DataType const varibleName;

 int const x;
    x=4; //you can assign its value only One time
(2) Оголосити вказівник на постійну змінну
const dataType* PointerVaribleName=&X;
 const int* ptr = &X;
     //Here pointer variable refer contents of 'X' that is const Such that its cannot be modified
dataType* const PointerVaribleName=&X;
 int* const ptr = &X;
     //Here pointer variable itself is constant  Such that value of 'X'  can be modified But pointer can't be modified


Ми надаємо змінну вказівника як const на функцію як аргумент, коли ми не хочемо змінити її фактичне значення
Pyadav
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.