По шагово, как это все работает,
сначала создется обект string из const char *
потом возвращается значение, делается return.
В этот момент стек еще живой, или уже нет?
A someObject;
string s = someObject.getSomething();
cхематично
string s = return "something";
"something" было создано в стеке, который должен очится
после завершения метода, вопрос в следующем, что раньше
произойдет, присвоение string s = "something", или чистка стека?
Выполняться это будет так. У класса string есть конструктор: string::string( const char* ), что по понятиям C++ эквивалентно наличию преобразования типов (const char*)->string, соответственно, в этом случае, оно и будет выполнено вызовом этого конструктора для объекта результата, расположенного на стеке.
Стек в этот момент будет ещё живой, но какое это имеет значение? :)
сам литерал "something" хранится не в стеке. Это статическая память.
Когда внутри функции делается return "something" это эквивалентно return string( "something" );
то есть конструктору string передается указатель на статическую память где лежит строчка something. Он ее копирует внутрь себя. Формально этот вновьобразованный объект string создается на стеке. После этого делается return и так как ты возвращаешь объект а не ссылку то вызывается конструктор копирования с аргументом -- вот этим объектом string. А получатель результата получает результат этого конструктора копирования..
Реально компилятор может соптимизировать и будет одно копирование а не два.
Спасибо огромное, все мои сомнения развеяны, не смотря на то,
что прошляпил что строковые константы выделяются в глобальной куче(а
ведь читал Страуструпа :-) )
Имхо не-ламерский совет: _никогда_ не возвращать ссылку/указатель (но ссылка это еще хуже, чем указатель) на поле объекта!
Гораздо лучше делать get/set методы.
Возврат ссылки опасен в случае, если объект на которыый ссылка указывает может в один прекрасный момент уничтожиться (вариантов масса - выход за пределы области видимости, delete ...)
Другой пример - ошибка, обнаруживаемая еще на этапе компиляции - если функция принимает аргумент по ссылке, а при вызове в нее передается костантное выражение:
void func(int& arg){
//...
}
//...
func(10);
Еще более замороченный случай: Функция принимает аргумент по ссылке,
а при вызове в нее передается разыменованный нулевой/мусорный указатель - в этом случае компилятор ошибки не замечает, а при вызове получаем сегфолт, о причине которого можно долго думать.
void func(int& i){
int j = i;
}
int* i; func(*i);
ИМХО - здесь то ли недоработка стандарта, то ли компилятора - то идее нужно кидать исключение в момент *i - ан нет: все накернится только когда произойдет реальное обращение к ресурсу.
Например:
void func(int& i){
int j = 10;//... i - не трогаем
}
int *i; func(*i);
Здесь программа отработает без ошибок несмотря на наличие разыменовывания невалидного указателя.