Может ли константная корректность улучшить производительность?


92

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

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


50
Постоянная корректность - одна из ЛУЧШИХ практик с точки зрения ремонтопригодности. Если ваш код на C ++ не является корректным по константе, это, по сути, куча дерьма, ожидающая катастрофы. Это не должно влиять на производительность.

2
@ Нил Баттерворт: к сожалению, обратное неверно.
Бета

6
Вот пример constразницы в производительности: stackoverflow.com/questions/1121791/… . Однако по сути это была проблема качества реализации. constне определить , является ли компилятор может законно сделать оптимизацию, просто так получилось , что версия компилятора не в состоянии сделать это , когда он отсутствовал.
Стив Джессоп,

3
Я совершенно уверен, что «morgennebel» пропустил «только» в первом предложении: это имеет больше смысла с «не только хорошая практика».
IanH

2
@IanH Да, я думал об этом. Но у ОП было достаточно времени, чтобы прояснить ситуацию. Меня очень раздражают люди, которые задают вопросы, а затем просто исчезают.

Ответы:


77

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

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

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

Не используйте constпо соображениям производительности. Используйте его из соображений ремонтопригодности.


31
"Вы бы могли поиграть с внутренним буфером струны!" - что особенно важно, вы можете случайно испортить внутренний буфер. Ошибки компилятора - constэто указатели, говорящие: «Вы делаете что-то глупое».
Стив Джессоп,

4
... и константные приведения - это указатели, говорящие: «Автор этого кода пытается сделать что-то умное» ;-)
Стив Джессоп

5
@Steve Jessop - или const-cast - это указатели, говорящие: «Я пытаюсь соединить константно-правильный код с неконстантно-правильным, и я не могу исправить ни один из них». Что, позвольте мне сказать, никоим образом не умно, а просто раздражает.
Майкл Кон

7
@Michael - да, справедливо. Возможно, исходный указатель не «вы делаете что-то глупое», а скорее «кто-то делает что-то глупое».
Стив Джессоп,

Годболт и Ардуино сказали мне, что правильность 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;
}

как м:

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 Вот почему я не упомянул компилятор в ответе. Обычно при публикации сгенерированной сборки я обязательно указываю компилятор и версию, но это оптимизация, которую будет выполнять каждый основной оптимизирующий компилятор, поэтому я не хотел создавать впечатление, что это было специфично для одного компилятора.
Praxeolitic

1
@Acorn Вот тот же пример, но с объектом класса: godbolt.org/z/R-Zfgc . Кроме того, переменные в примере имеют внешнюю связь.
Praxeolitic

6

по моему опыту нет

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

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

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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.