Подтвердить что ты не робот

Какую оптимизацию предлагает const в C/C++?

Я знаю, что, когда это возможно, вы должны использовать ключевое слово const при передаче параметров по ссылке или по указателю для удобства чтения. Есть ли какие-либо оптимизации, которые может выполнить компилятор, если я укажу, что аргумент постоянный?

Может быть несколько случаев:

Параметры функции:

Постоянная ссылка:

void foo(const SomeClass& obj)

Постоянный объект SomeClass:

void foo(const SomeClass* pObj)

И постоянный указатель на SomeClass:

void foo(SomeClass* const pObj)

Объявления переменных:

const int i = 1234

Объявление функций:

const char* foo()

Какую оптимизацию компилятора предлагает каждый (если есть)?

4b9b3361

Ответ 1

[Читатели учтут, что большая часть этой публикации снята из статьи Херба Саттера - http://www.gotw.ca/gotw/081.htm - без атрибуции OP.]

CASE_1: -

Когда вы объявляете const в своей программе,

int const x = 2;

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

ПРИМЕЧАНИЕ. - Если вы делаете что-то вроде: -

const int x = 1;
const int* y = &x;

Затем это заставит компилятор выделить пространство для 'x'. Таким образом, эта степень оптимизации для этого случая невозможна.

В терминах параметров функции const означает, что параметр не изменяется в функции. Насколько я знаю, нет существенного прироста производительности для использования const, а это средство для обеспечения правильности.

CASE_2: -

"Объявляет ли параметр и/или возвращаемое значение const, чтобы компилятор мог создать более оптимальный код?"

  const Y& f( const X& x )
  {
    // ... do something with x and find a Y object ...
    return someY;
  }

Ques = > Что может сделать компилятор лучше?

= > Не удалось ли копировать параметр или возвращаемое значение?

Нет, поскольку аргумент уже передан по ссылке.

= > Может ли он поместить копию x или someY в постоянную память?

Нет, поскольку и х, и некоторые из них живут вне его сферы действия и поступают из и/или передаются во внешний мир. Даже если какой-либо Я динамически выделяется "на лету" внутри самого f(), он и его собственность передаются вызывающему.

Ques = > Как насчет возможных оптимизаций кода, который появляется внутри тела f()? Из-за const, может ли компилятор каким-то образом улучшить код, который он генерирует для тела f()?

Даже когда вы вызываете функцию-член const, компилятор не может предположить, что биты объекта x или объекта someY не будут изменены. Кроме того, есть дополнительные проблемы (если компилятор не выполняет глобальную оптимизацию): компилятор также может не знать наверняка, что ни один другой код не может иметь неконстантную ссылку, которая псевдонизирует тот же объект, что и x и/или someY, и есть ли такой неконстантные ссылки на один и тот же объект могут использоваться случайно во время выполнения f(); и компилятор может даже не знать, действительно ли реальные объекты, к которым x и некоторые Y являются просто ссылками, фактически были объявлены как const.

CASE_3: -

  void f( const Z z )
  {
    // ...
  }

Ques = > Будет ли в этом оптимизация?

Да, потому что компилятор знает, что z действительно является объектом const, он может выполнять некоторые полезные оптимизации даже без глобального анализа. Например, если тело f() содержит вызов типа g (& z), компилятор может быть уверен, что не изменяемые части z не изменяются во время вызова g()

Ответ 2

Прежде чем дать какой-либо ответ, я хочу подчеркнуть, что причина использования или не использования const действительно должна быть для правильности программы и для большей ясности для других разработчиков, а не для оптимизации компилятора; то есть создание параметра const документов, что метод не будет изменять этот параметр, и делает функцию-член const документом, что этот член не будет изменять объект, членом которого он является (по крайней мере, не так, логически изменяет вывод из любой другой функции-члена-константы). Например, это позволяет разработчикам избежать ненужных копий объектов (потому что им не нужно беспокоиться о том, что оригинал будет уничтожен или изменен) или во избежание ненужной синхронизации потоков (например, зная, что все потоки просто читают и делают не мутировать объект, о котором идет речь).

Что касается оптимизаций, которые компилятор мог бы сделать, по крайней мере теоретически, хотя и в режиме оптимизации, что позволяет ему выполнять определенные нестандартные предположения, которые могут нарушить стандартный код на С++, рассмотрим:

for (int i = 0; i < obj.length(); ++i) {
   f(obj);
}

Предположим, что функция length отмечена как const, но на самом деле является дорогостоящей операцией (предположим, что она фактически работает в O (n) раз, а не O (1) раз). Если функция f принимает свой параметр с помощью ссылки const, тогда компилятор может потенциально оптимизировать этот цикл для:

int cached_length = obj.length();
for (int i = 0; i < cached_length; ++i) {
   f(obj);
}

... поскольку тот факт, что функция f не изменяет параметр, гарантирует, что функция length должна возвращать одинаковые значения каждый раз, когда объект не изменился. Однако, если объявлено, что f принимает параметр с помощью изменяемой ссылки, тогда length нужно будет пересчитать на каждой итерации цикла, так как f мог бы изменить объект таким образом, чтобы произвести изменение в значение.

Как указано в комментариях, это предполагает ряд дополнительных предостережений и будет возможно только при вызове компилятора в нестандартном режиме, что позволяет ему делать дополнительные предположения (например, методы const строго функция их входов и оптимизации можно предположить, что код никогда не будут использовать const_cast преобразовать константный ссылочный параметр на изменяемую ссылку).

Ответ 3

Параметры функции:

const не имеет значения для ссылочной памяти. Это как привязка руки за оптимизатором.

Предположим, вы вызываете другую функцию (например, void bar()) в foo, которая не имеет видимого определения. Оптимизатор будет иметь ограничение, поскольку он не знает, изменил ли параметр bar параметр функции, переданный в foo (например, через доступ к глобальной памяти). Потенциал для изменения внешней памяти и псевдонимов создает значительные ограничения для оптимизаторов в этой области.

Хотя вы не спрашивали, значения const для параметров функции позволяют оптимизировать, поскольку оптимизатору гарантирован объект const. Конечно, стоимость копирования этого параметра может быть намного выше, чем преимущества оптимизатора.

Смотрите: http://www.gotw.ca/gotw/081.htm


Переменные объявления: const int i = 1234

Это зависит от того, где он объявлен, когда он создан, и типа. Эта категория в значительной степени существует там, где существуют оптимизации const. undefined изменять объект const или известную константу, поэтому компилятору разрешено выполнять некоторые оптимизации; предполагается, что вы не вызываете поведение undefined и получаете некоторые гарантии.

const int A(10);
foo(A);
// compiler can assume A not been modified by foo

Очевидно, что оптимизатор также может идентифицировать переменные, которые не меняются:

for (int i(0), n(10); i < n; ++i) { // << n is not const
 std::cout << i << ' ';
}

Объявление функций: const char* foo()

Не важно. Зарезервированная память может быть изменена извне. Если ссылочная переменная, возвращаемая foo, видна, оптимизатор может сделать оптимизацию, но это не имеет ничего общего с наличием/отсутствием const в возвращаемом типе функции.

Опять же, значение или объект const отличается:

extern const char foo[];

Ответ 4

SomeClass* const pObj создает постоянный объект типа указателя. Существует не безопасный метод изменения такого объекта, поэтому компилятор может, например, кэшировать его в регистр с чтением только одного считывания, даже если его адрес занят.

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

Ответ 5

Точные эффекты const различаются для каждого контекста, в котором он используется. Если const используется при объявлении переменной, она физически const и сильно находится в постоянной памяти.

const int x = 123;

Пытаться отбросить консистенцию будет undefined behavour:

Даже несмотря на то, что const_cast может удалить константу или волатильность от любого указателя или ссылки, используя результирующий указатель или ссылку на запись в объект, который был объявлен const или для доступа к объявленному пользователем volatile вызывает поведение undefined. cppreference/const_cast

Итак, в этом случае компилятор может предположить, что значение x всегда 123. Это открывает некоторый потенциал оптимизации (распространение констант)

Для функций это другое дело. Пусть:

void doFancyStuff(const MyObject& o);

наша функция doFancyStuff может выполнять любую из следующих операций с помощью o.

  • не изменять объект.
  • отбросить константу, а затем изменить объект
  • измените mutable элемент данных MyObject

Обратите внимание, что если вы вызываете нашу функцию с экземпляром MyObject, который был объявлен как const, вы будете вызывать поведение undefined С# 2.

Вопрос с гуру: будут ли следующие вызовы undefined?

const int x = 1;
auto lam = [x]() mutable {const_cast<int&>(x) = 2;};
lam();