Предоставляет ли C ++ гарантию на время жизни временной переменной, которая создается при вызове функции, но не используется в качестве параметра? Вот пример класса:
class StringBuffer
{
public:
StringBuffer(std::string & str) : m_str(str)
{
m_buffer.push_back(0);
}
~StringBuffer()
{
m_str = &m_buffer[0];
}
char * Size(int maxlength)
{
m_buffer.resize(maxlength + 1, 0);
return &m_buffer[0];
}
private:
std::string & m_str;
std::vector<char> m_buffer;
};
И вот как бы вы это использовали:
// this is from a crusty old API that can't be changed
void GetString(char * str, int maxlength);
std::string mystring;
GetString(StringBuffer(mystring).Size(MAXLEN), MAXLEN);
Когда будет вызван деструктор временного объекта StringBuffer? Это:
- Перед вызовом GetString?
- После возвращения GetString?
- Зависит от компилятора?
Я знаю, что C ++ гарантирует, что локальная временная переменная будет действительна до тех пор, пока на нее есть ссылка - применимо ли это к родительским объектам, когда есть ссылка на переменную-член?
Спасибо.
m_str.reserve(maxlength)
вchar * Size(int maxlength)
противном случае деструктор может бросить.Ответы:
Деструктор для такого рода временных файлов вызывается в конце полного выражения. Это самое внешнее выражение, которое не является частью любого другого выражения. Это в вашем случае после возврата функции и оценки значения. Так что все будет хорошо работать.
Фактически, это то, что заставляет шаблоны выражений работать: они могут содержать ссылки на такого рода временные объекты в выражении вроде
Потому что каждое временное будет длиться до выражения
Оценивается полностью. Это довольно лаконично описано в
12.2 Temporary objects
Стандарте.источник
printf("%s", strdup(std::string("$$$").c_str()) );
Я имею в виду, что еслиstrdup(std::string("$$$").c_str())
оно принимается как полное выражение, то указатель, которыйstrdup
видит, действителен . Еслиstd::string("$$$").c_str()
это полное выражение, значит указатель, которыйstrdup
видит, недействителен ! Не могли бы вы объяснить немного больше на этом примере?printf
- полное выражение. Таким образом,strdup
это ненужная утечка памяти - вы можете просто позволить ейc_str()
напрямую распечатать .litb ответ точен. Время жизни временного объекта (также известного как rvalue) привязано к выражению, и деструктор для временного объекта вызывается в конце полного выражения, и когда вызывается деструктор в StringBuffer, деструктор в m_buffer также будет вызывается, но не деструктором на m_str, поскольку это ссылка.
Обратите внимание, что C ++ 0x немного меняет ситуацию, потому что он добавляет ссылки на rvalue и семантику перемещения. По сути, используя ссылочный параметр rvalue (обозначенный &&), я могу «переместить» rvalue в функцию (вместо того, чтобы копировать его), и время жизни rvalue можно привязать к объекту, в который он перемещается, а не к выражению. Есть действительно хороший пост в блоге от команды MSVC, в котором это подробно рассматривается, и я призываю людей прочитать его.
Педагогическим примером перемещения rvalue являются временные строки, и я покажу присваивание в конструкторе. Если у меня есть класс MyType, содержащий строковую переменную-член, его можно инициализировать с помощью rvalue в конструкторе следующим образом:
Это хорошо, потому что когда я объявляю экземпляр этого класса временным объектом:
происходит то, что мы избегаем копирования и уничтожения временного объекта, и «привет» помещается непосредственно внутри переменной-члена экземпляра класса-владельца. Если объект тяжелее, чем «строка», то дополнительная копия и вызов деструктора могут иметь значение.
источник
После вызова GetString возвращается.
источник
StringBuffer находится в сфере GetString. Он должен быть уничтожен в конце области действия GetString (т.е. когда он вернется). Кроме того, я не верю, что C ++ гарантирует, что переменная будет существовать до тех пор, пока есть ссылка.
Следующее должно компилироваться:
источник
Я написал почти такой же класс:
До появления стандарта каждый компилятор делал это по-своему. Я считаю, что в старом аннотированном справочном руководстве для C ++ указано, что временные библиотеки должны очищаться в конце области видимости, поэтому некоторые компиляторы сделали это. Еще в 2003 году я обнаружил, что такое поведение по умолчанию все еще существует в компиляторе Sun Forte C ++, поэтому StringBuffer не работал. Но я был бы удивлен, если бы какой-нибудь текущий компилятор все еще был сломан.
источник