Продай мені на правильності конкуренції


133

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

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

  2. Чи є переваги використання сопзЬ дійсно досить , щоб компенсувати проблеми? Якщо ви не збираєтесь змінювати об'єкт, чому б просто не написати код, який не змінить його?

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


1
8 років стара ретроспектива, але .. Як щодо прискорення коду 100x (бачили це в прямому ефірі)?
lorro

1
Ознайомтесь з моєю відповіддю тут (пов'язане запитання, я би сказав те саме): stackoverflow.com/questions/42310477/… BTW: Я люблюconst
Gines Hidalgo

Відповіді:


158

Це остаточна стаття про "правильність const": https://isocpp.org/wiki/faq/const-correctness .

Коротше кажучи, використання const є хорошою практикою, оскільки ...

  1. Він захищає вас від випадкових змін змінних, які не призначені для зміни,
  2. Він захищає вас від присвоєння випадкових змінних та
  3. Компілятор може оптимізувати його. Наприклад, ви захищені від

    if( x = y ) // whoops, meant if( x == y )

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

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


Я завжди припускав, що значення const можна вільно кешувати і, таким чином, уникати багатьох проблем одночасності або покращувати швидкість. Це правда?
Phil H

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

4
Як і для C ++ 11, стандартна бібліотека також передбачає constбезпеку потоків та обробку власного коду. Це полегшує перевірку можливих проблем із багатопотоковою передачею та є простим способом надання гарантій API для користувачів API.
pmr

3
Для мене одне з найбільших надбавок правильності const - це те, що ви знаєте, просто дивлячись на прототипи функцій, коли покажчики посилаються на дані, які ніколи не мутуються функцією (тобто лише вхідними даними).
cp.engr

1
Не варто забувати , що є логічна і фізична константность. Будь-який об'єднаний об'єкт, який позначений як змінний, може змінюватися, хоча маркування його як такого означає, що він не має нічого спільного з логічною обмеженістю об'єкта, що міститься.
Адріан

128

Ось фрагмент коду із поширеною помилкою, що правильність const може захистити вас від:

void foo(const int DEFCON)
{
   if (DEFCON = 1)     //< FLAGGED AS COMPILER ERROR! WORLD SAVED!
   {
       fire_missiles();
   }
}

19
Отже, ми говоримо, що const необхідний тому, що якийсь кривавий ідіот вибрав "=" в якості оператора призначення C? ;-)
Стів Джессоп,

37
Звичайно, більшість сучасних компіляторів попереджають про завдання в умовних умовах, і всі ми включаємо попередження про трактування як прапор помилок, правильно: ->
Jack Bolding

7
Не будьте занадто жорстким на цьому прикладі: Це той самий приклад, який є євангелізований деякими розробниками, щоб переконати нас використовувати if (0 == i) замість if (i == 0). Нарешті, шаблон коду Дуга може бути використаний поза оператором "якщо". Що важливо, це показує одну з переваг const у жартівливій формі. + 1.
paercebal

2
Деякі компілятори (і вказівки) попереджають про це вже давно, і це набагато корисніше, щоб зловити цю помилку, ніж const: codepad.org/Nnf5JUXV .

7
@Roger ви припускаєте, що ми живемо у світі, де конструкції чисті та без попередження. Мій досвід полягає в тому, що в багатьох кодових попередженнях губиться шум. Крім того, існує багато коду, який виконує завдання в виразі if, і багато хто буде стверджувати, що це дійсний, "хороший" стиль.
Дуг Т.

62

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

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


7
Це допомогло мені запобігти стільки помилок, де я мав функцію const щодо виклику функції non-const, оскільки я забув, що вона змінює дані під ними.
Mooing Duck

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

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

4
"Якщо ви проектуєте const-правильне з самого початку", скільки разів ви насправді маєте розкіш, щоб з самого початку вимушувати правильність const ?? Більшості з нас доводиться щодня працювати з численними API та бібліотеками, де це не так, і з цим можна зробити мало. Тож я погоджуюся з настроями ОП "Схоже, щоразу, коли я щось відзначаю як const, я отримую помилку" ...
nyholku

@WarrenDew Це перехідний аргумент; якби оригінальні автори використовували constналежним чином (тобто "з самого початку"), то справді не виникло б проблеми, в чому саме справа!
Гонки легкості по орбіті

31

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


1
Це лише така правда. Const також використовується як захист для забезпечення введення змінних через інтерфейси тощо.
Джордан Пармер

Так є, але ви можете застосувати це за допомогою дисциплінованих методів кодування та плаката. Реальна вигода від цього відображається в API.
Антоніо Хейлі

2
Саме так. Краще мати "const int Value = 5;" ніж у "int ConstValue = 5;". +1.
paercebal

6
Правильний час для коректності const - це коли ви пишете API спочатку. Інакше ви потрапите в проблеми із отруєнням констатом, коли переобладнаєте його (саме тому додавання його до старого коду - зовсім інша справа, як це робити в новому коді).
Стипендіати Доналу

@DonalFellows це не говорить про те, що додано const пізніше. Це означає, що пільги ви отримуєте пізніше, коли читаєте код з const, який вже присутній
Caleth

27

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


1
оскільки C ++ 17 і доброта constexpr я пишу складати тести одиниці часу ... все ближче досі ...
QBziZ

22

const - це обіцянка, яку ви даєте як розробник, і залучаєте допомогу компілятора у виконанні.

Мої причини бути коректними:

  • Він повідомляє клієнтам вашої функції, що ви не будете змінювати змінну чи об'єкт
  • Прийняття аргументів за допомогою посилання const дає вам ефективність передачі посилання з безпекою передачі за значенням.
  • Запис інтерфейсів як правильних const дозволить клієнтам використовувати їх. Якщо ви пишете свій інтерфейс для отримання посилань, які не мають const, клієнтам, які використовують const, потрібно буде відмовитись від constness, щоб працювати з вами. Це особливо дратує, якщо ваш інтерфейс приймає символи non-con char *, а ваші клієнти використовують std :: string, оскільки ви можете отримати лише const char * від них.
  • Використання const залучає компілятора до того, щоб бути чесним, щоб ви не помилково змінили щось, що не повинно змінитися.

20

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


20

Програмування на C ++ без обмежень - це як їзда без включеного ременя безпеки.

Боляче ставити ремінь безпеки кожен раз, коли ви ступаєте в машину, і 364 з 365 днів ви приїдете безпечно.

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


18

Для вбудованого програмування constрозумне використання глобальних структур даних може заощадити багато оперативної пам’яті, викликаючи розташування постійних даних у ПЗУ або спалах без копіювання в ОЗУ під час завантаження.

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

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


13

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

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

Приклад:

#include <iostream>

class HelloWorld {
    bool hw_called;

public:
    HelloWorld() : hw_called(false) {}

    void hw() const {
        std::cout << "Hello, world! (const)\n";
        // hw_called = true;  <-- not allowed
    }

    void hw() {
        std::cout << "Hello, world! (non-const)\n";
        hw_called = true;
    }
};

int
main()
{
    HelloWorld hw;
    HelloWorld* phw1(&hw);
    HelloWorld const* phw2(&hw);

    hw.hw();    // calls non-const version
    phw1->hw(); // calls non-const version
    phw2->hw(); // calls const version
    return 0;
}

13

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

У багатьох кодах, які я пишу, справді варто було докласти зусиль, тому що ми, як правило, використовуємо склад:

class A { ... }
class B { A m_a; const A& getA() const { return m_a; } };

Якби у нас не було коректності, тоді вам доведеться вдаватися до повернення складних об'єктів за значенням, щоб переконатись у тому, що за вашою спиною ніхто не маніпулював внутрішнім станом класу В.

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


7

Скажімо, у вас є змінна в Python. Ви знаєте, що ви не повинні його змінювати. Що робити, якщо ви випадково зробите?

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


4

Існує гарна стаття тут про Const в C ++. Це досить відверта думка, але сподіваюся, що це допомагає деяким.


3

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

Так, з часом стає простіше.


2

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

Можливо, це просто дизайнерські зразки, які я використовую, але const завжди стає занадто широкою кистю.

Наприклад, уявіть собі простий двигун бази даних ... у ньому є об'єкти схеми, таблиці, поля тощо. Користувач може мати вказівник 'таблиця const', що означає, що їм заборонено змінювати саму схему таблиці ... а що стосується маніпулювання дані, пов'язані з таблицею? Якщо метод Insert () позначений const, то внутрішньо він повинен відкинути const-ness, щоб фактично маніпулювати базою даних. Якщо він не позначений const, він не захищає від виклику методу AddField.

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


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

2
Коли функція Insert () коли-небудь буде позначена як const, якщо вона не була названа неправильно? Додавання речей зазвичай модифікує те, до чого ви її додали, тобто це не const. Те, що ви дійсно хотіли, це TableWithConstSchema.
Грег Роджерс,

Я можу додати ще один клас, але я не хочу робити API надмірно складним виключно заради const-коректності.
Роб Уокер

1

Ви можете дати підказки для компілятора з const також .... відповідно до наступного коду

#include <string>

void f(const std::string& s)
{

}
void x( std::string& x)
{
}
void main()
{
    f("blah");
    x("blah");   // won't compile...
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.