В следующем коде строка инкапсулирована в класс Foo.
Вызов Foo :: getText () возвращает строку по значению. Это создает второй экземпляр строкового объекта, но теперь оба строковых объекта указывают на один и тот же буфер символов в куче.
Когда экземпляр Foo удаляется, инкапсулированная строка автоматически уничтожается, и поэтому буфер символов в куче удаляется.
Несмотря на то, что getText()
возвращает строку по значению, результирующий строковый объект по-прежнему полагается на время жизни исходного строкового объекта, чтобы сохранить буфер символов, на который они взаимно указывают.
Разве это не означает, что печать retval
на терминал является недопустимым доступом к памяти, которая уже была освобождена в куче?
class Foo
{
Foo(const char* text) :
str(text)
{
}
std::string getText()
{
return str;
}
std::string str;
};
int main()
{
Foo pFoo = new Foo("text");
std::string retval = foo.getText();
delete pFoo;
cout << retval; // invalid memory access to char buffer?
}
Я думаю, что многие люди предполагают, что, поскольку строка была возвращена по значению, им не нужно беспокоиться о времени жизни исходной строки в Foo. Эта проблема не связана строго со строками, но действительно применима к любому классу с инкапсулированными указателями, которые освобождаются при уничтожении. Но что здесь лучше всего, когда дело доходит до струнных?
- Никогда не возвращать строку по значению?
- Возвращать строки только по значению, если время жизни исходной строки гарантировано?
- Всегда делать копию строки?
return std::string(retval.c_str());
- Обеспечить соблюдение контракта с вызывающим абонентом
getText()
?
РЕДАКТИРОВАТЬ:
Я думаю, что меня ввело в заблуждение РВО. Все три строки в этом примере возвращают c_str по одному и тому же адресу. Виноват РВО?
class Obj
{
public:
Obj() : s("text")
{
std::printf("%p\n", s.c_str());
}
std::string getText() { return s; }
std::string s;
};
int main()
{
Obj* pObj = new Obj();
std::string s1(pObj->getText());
std::string s2 = pObj->getText();
delete pObj;
std::printf("%p\n", s1.c_str());
std::printf("%p\n", s2.c_str());
}
Результат:
0x600022888
0x600022888
0x600022888
std::string
, а не оstd::vector
. Еще одна неудачная попытка. - person Lightness Races in Orbit   schedule 24.06.2016c_str
вернет что-либо, даже напоминающее внутреннее представление. - person user4581301   schedule 24.06.2016