Предположим, что вы хотели объявить переменную, как уже отмечалось:
void foo() {
// {before}
MyClass m;
// {after}
}
Затем семантически , конструктор выполняется после {before} и до {после} .
Подлежит ли это правилу во время выполнения, как правило, как если бы.То есть для обеспечения оптимизации Стандарт предлагает только гарантии о наблюдаемых эффектах: независимо от выбранной модели выполнения наблюдаемые эффекты должны быть такими, как если бы код был выполнен без какой-либо оптимизации.
Наблюдаемые эффекты, в частности, включают:
- модификация
volatile
переменных - системных вызовов (включая операции с памятью)
По умолчанию функцияопределение которого неизвестно, как предполагается, имеет наблюдаемые эффекты.
Заметным исключением является оптимизация Copy Elision , которую Стандарт допускает в ряде случаев, даже если конструктор копирования может иметь наблюдаемые эффекты.
Конкретно, это означает, что с учетом:
int before();
int after();
void foo() {
int n = 5;
int const a = before();
n += a;
MyClass m;
int const c = after();
n += c;
std::cout << n << "\n";
}
Стандарт гарантирует следующий порядок:
before();
MyClass m;
after();
std::cout << n << "\n";
Однако не гарантируется, как вычисляется n
.Все, что известно, это то, что в момент его печати оно будет равно 5 + a + c
, но не имеет значения, задерживается ли вычисление непосредственно перед печатью или выполняется с нетерпением каждый раз, когда появляется новый элемент:не изменяет наблюдаемое поведение.
Следовательно, две следующие версии foo
эквивалентны:
void foo_eager() {
int n = 5;
n += before();
MyClass m;
n += after();
std::cout << n << "\n";
}
void foo_lazy() {
int const a = before();
MyClass m;
int const c = after();
std::cout << (5 + a + c) << "\n";
}