Когда временные значения параметров выходят за рамки?
Возможный дубликат:
Время жизни во времени
int LegacyFunction(const char *s) {
// do something with s, like print it to standard output
// this function does NOT retain any pointer to s after it returns.
return strlen(s);
}
std::string ModernFunction() {
// do something that returns a string
return "Hello";
}
LegacyFunction(ModernFunction().c_str());
Приведенный выше пример может быть легко переписан для использования интеллектуальных указателей вместо строк; Я встречал обе эти ситуации много раз. Во всяком случае, в приведенном выше примере будет построена строка STL в ModernFunction, верните ее, затем получите указатель на строку C-стиля внутри строкового объекта и затем передайте этот указатель на унаследованную функцию.
- Существует временный объект строки, который существует после возврата функции ModernFunction. Когда это выходит за рамки?
- Возможно ли, чтобы компилятор вызывал c_str(), уничтожал этот временный объект строки, а затем передал висячий указатель на LegacyFunction? (Помните, что строковый объект управляет памятью, в которой значение c_str() возвращает значение...)
- Если приведенный выше код небезопасен, почему он небезопасен, и есть ли лучший, не менее краткий способ его записи, чем добавление временной переменной при выполнении вызовов функций? Если это безопасно, почему?
Ответы
Ответ 1
LegacyFunction(ModernFunction().c_str());
Уничтожение копии будет после оценки full expression
(т.е. после возврата из LegacyFunction
).
n3337 12,2/3
Временные объекты уничтожаются как последний шаг
при оценке полного выражения (1.9), которое (лексически) содержит точку, в которой они были созданы.
n3337 1,9/10
Полное выражение - это выражение, которое не является подвыражением другого выражения. Если языковая конструкция
определяется для получения неявного вызова функции, использование языковой конструкции считается
выражения для целей этого определения. Вызов деструктора, сгенерированного в конце
объект, отличный от временного объекта, является неявным полным выражением. Конверсии, применяемые к результату
выражение для удовлетворения требований языковой конструкции, в которой появляется выражение
также считаются частью полного выражения.
[Пример:
struct S {
S(int i): I(i) { }
int& v() { return I; }
private:
int I;
};
S s1(1); // full-expression is call of S::S(int)
S s2 = 2; // full-expression is call of S::S(int)
void f() {
if (S(3).v()) // full-expression includes lvalue-to-rvalue and
// int to bool conversions, performed before
// temporary is deleted at end of full-expression
{ }
}
Ответ 2
Существует временный объект строки, который существует после возврата функции ModernFunction. Когда это выходит за рамки?
Строго говоря, это никогда не имеет границ. Область действия - это свойство имени, а не объекта. Так получилось, что автоматические переменные имеют очень тесную связь между областью действия и временем жизни. Объекты, которые не являются автоматическими переменными, различны.
Временные объекты уничтожаются в конце полного выражения, в котором они появляются, с несколькими исключениями, которые здесь не актуальны. В любом случае, особые случаи продлевают время жизни временного, они не уменьшают его.
Возможно ли, чтобы компилятор вызывал c_str(), уничтожал этот временный объект строки, а затем передавал оборванный указатель на LegacyFunction
Нет, потому что полное выражение LegacyFunction(ModernFunction().c_str())
(исключая точку с запятой: чувствуйте, что педантизм), поэтому временное значение, которое является возвращаемым значением ModernFunction
, не уничтожается до тех пор, пока LegacyFunction
не вернется.
Если это безопасно, почему?
Потому что время жизни временного достаточно.
В общем случае с c_str
вам нужно беспокоиться о двух вещах. Во-первых, возвращаемый указатель становится недействительным, если строка уничтожается (это то, что вы просите). Во-вторых, возвращаемый указатель становится недействительным, если строка изменена. Вы не беспокоитесь об этом здесь, но это нормально, вам не нужно, потому что ничто не изменяет строку.