Условные переменные стека
Учитывая следующую функцию, будет ли объявлена каждая из локальных переменных в стеке?
std::string reallyCoolFunction(unsigned int a)
{
if( a < 20 )
{
std::string result1 = "This function is really cool";
return result1;
}
if( a >=20 && a <= 40 )
{
std::string result2 = "This function is kind of cool";
return result2;
}
if( a > 40 )
{
std::string result3 = "This function is moderately cool";
return result3;
}
std::string result4 = "This function really isn't that cool";
return result4; // remove warning
}
В этой ситуации требуется только один std::string
, все ли 4 выделяются в стеке или выделяются только 1?
Ответы
Ответ 1
Решение зависит от компилятора: поскольку автоматические переменные выходят за пределы области действия до того, как следующий приходит в область видимости, компилятор может повторно использовать свою память. Имейте в виду, что переменные "stack" на самом деле являются переменными с автоматической продолжительностью хранения в соответствии со спецификацией С++, поэтому они могут вообще не находиться в стеке.
Ответ 2
В большинстве компиляторов будет выделена только одна строка. Имейте в виду, что std::string
использует динамическую память, поэтому большая часть ее содержимого по-прежнему будет выделена в куче.
Ответ 3
Скорее всего 0 или, может быть, 1 (в выпуске) и, конечно, 4 (в отладке).
Это называется RVO: Оптимизация возвращаемого значения.
Компилятору разрешено полностью исключить копию и построить std::string
непосредственно в слоте, предоставленном вызывающим. Это спецификация ABI, и поскольку все оптимизации применяются только в том случае, если выполняется ряд критериев; в вашем случае вероятно, что оно будет применяться.
Если вы хотите проверить, вы можете попытаться просмотреть выход компилятора на разных этапах его проекта перевода/оптимизации; это может быть сложно, хотя в зависимости от вашей инструментальной цепочки.
Ответ 4
Зависит от компилятора.
Если компилятор достаточно интеллектуальный, чтобы окончательно определить, что требуется только одна строка, он будет генерировать код только для одной строки.
Является ли ваш компилятор достаточно умным?
Самый простой способ - проверить сгенерированный код сборки.
Все ли 4 выделены в стеке или выделено только 1?
Будь это 1 или 4 строки, строковый объект находится в стеке, локальном для функции, но память для строки выделяется в freestore.
Ответ 5
В этом случае компилятору разрешено создавать 4, 1, 2 или 3 переменные. Но большинство компиляторов, о которых я знаю, создавали бы только один или, возможно, два, поскольку результат4 находится во всей области действия функции.
Конечно, если вы делаете "правильные" вещи, компилятор может запутаться и сделать больше, чем это абсолютно необходимо, поэтому полагаться на это в критической функциональности не будет особенно хорошо.
Изменить: я должен добавить, что конструктор для std::string должен запускаться только в том случае, если объект фактически "используется", поэтому вы можете получить используемое пространство стека, но он не должен вызывать конструктор. Это важно, если вы делаете что-то вроде этого:
void func()
{
if (something)
{
Lock myLock(&global_lock_object); // Constructor locks global_lock_object
... do stuff that needs global_lock_object locked ...
// end of scope runs destructor of Lock that unlocks global_lock_object.
}
... more code that takes a long time to execute but doesn't need lock. ...
}
Теперь, если конструктор для Lock
был выполнен "слишком рано" и разрушен в той же области видимости [и должен быть симметричным], блокировка будет удерживаться на протяжении всей функции, что было бы неправильно,
Ответ 6
Краткий ответ: посмотрите на ассемблер.
Длинный ответ: компилятор может применять статические проверки, чтобы определить, нужны ли ему все 4 или только некоторые из переменных. Некоторые компиляторы могут выделять 4 разных переменных в режиме отладки, а некоторые - нет. В режиме Release некоторые оптимизаторы могут видеть, что первые 3 являются отдельными в своей области и поэтому могут быть помещены в одно и то же место. Поэтому эти компиляторы могут зарезервировать место для двух строковых переменных в стеке. Ему нужно лишь немного больше анализа, чтобы увидеть, что четвертая переменная ни в коем случае не сосуществует с первыми тремя, поэтому некоторые оптимизаторы могут поместить оставшиеся две переменные в одно и то же место.
Но, делает ли ваш компилятор это и будет ли он делать это в чуть более сложной ситуации, может быть определен только в случае анализа вывода.