Чи може правильність const покращити ефективність?


92

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

Отже, чи є у вас приклади, коли коректність const може допомогти вашому компілятору покращити продуктивність вашої програми?


50
Конст-коректність - одна з НАЙКРАЩИХ практик щодо ремонтопридатності. Якщо ваш код на C ++ не правильний для const, це в основному купа лайна, яка чекає катастрофи. Він не призначений впливати на продуктивність.

2
@ Ніл Баттерворт: на жаль, зворотне не відповідає дійсності.
Бета

6
Ось приклад, коли constзмінилася продуктивність: stackoverflow.com/questions/1121791/… . По суті, це було питання якості реалізації. constНе визначено , є чи компілятор може законно зробити оптимізацію, просто так вийшло , що версія компілятора не в змозі зробити це , коли він був відсутній.
Steve Jessop

3
Я цілком впевнений, що "morgennebel" пропустив "тільки" у першому реченні: це має набагато більше сенсу, оскільки "це не лише хороша практика".
IanH

2
@IanH Так, я це вважав. Але в ОП було достатньо часу для роз'яснень. Мене дуже цікавлять люди, які розміщують запитання, а потім просто зникають.

Відповіді:


77

constПравильність не може поліпшити продуктивність , так const_castі mutableв мові, і дозволяють код conformingly порушувати правила. Це стає ще гіршим у C ++ 11, де ваші constдані можуть, наприклад, бути вказівником на a std::atomic, тобто компілятор повинен поважати зміни, внесені іншими потоками.

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

З усього сказаного, constправильність - це хороша річ щодо ремонтопридатності. В іншому випадку клієнти вашого класу можуть зламати внутрішніх членів цього класу. Наприклад, розглянемо стандарт std::string::c_str()- якщо він не може повернути значення const, ви зможете перекрутити внутрішній буфер рядка!

Не використовуйте constз міркувань продуктивності. Використовуйте його з міркувань ремонту.


31
"ви зможете перекрутити внутрішній буфер рядка!" - що найважливіше, ви могли б випадково перекрутити внутрішній буфер. Помилки компілятора через constвказівники, говорячи: "Ти робиш щось дурне".
Steve Jessop

4
... і const-casts - це покажчики, які говорять: "Автор цього коду намагається зробити щось розумне" ;-)
Стів Джессоп

5
@Steve Jessop - або const-cast - це покажчики, які говорять: "Я намагаюся зв'язати з правильним const-набором коду до неконтрольованого, і я не можу виправити жоден". Що, дозвольте вам сказати, жодним чином не розумне, просто дратує.
Michael Kohne

7
@Michael - так, справедлива думка. Можливо, оригінальний покажчик - це не "ти робиш щось дурне", а "хтось робить щось дурне".
Steve Jessop

Годболт і Ардуіно сказали мені, що коректність const - це не просто для задоволення.
dgrat

31

Так це може.

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

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

https://godbolt.org/g/UEX4NB

C ++:

int foo1 = 1;
const int foo2 = 2;

int get_foo1() {
    return foo1;
}

int get_foo2() {
    return foo2;
}

asm:

foo1:
        .long   1
foo2:
        .long   2
get_foo1():
        push    rbp
        mov     rbp, rsp
        mov     eax, DWORD PTR foo1[rip] ; foo1 must be accessed by address
        pop     rbp
        ret
get_foo2():
        push    rbp
        mov     rbp, rsp
        mov     eax, 2 ; foo2 has been replaced with an immediate 2
        pop     rbp
        ret

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


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


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

1
@Acorn Ось той самий приклад, але з об’єктом класу: godbolt.org/z/R-Zfgc . Крім того, змінні в прикладі мають зовнішній зв'язок.
Праксеоліт

6

з мого досвіду, ні

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

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

якщо ви шукаєте оптимізацію, вам слід розглянути __restrict__або спеціальні модифікатори / атрибути функцій: http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html


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