Относительно возвращения объектов функциями важно понимать следующее. Если функция возвращает объект класса, она автоматически создает временный объект, который хранит возвращаемое значение. Именно этот объект реально и возвращается функцией. После возврата значения объект разрушается. Разрушение временного объекта в некоторых ситуациях может вызвать непредвиденные побочные эффекты. Например, если объект, возвращаемый функцией, имеет деструктор, который освобождает динамически выделяемую память, эта память будет освобождена даже в том случае, если объект, получающий возвращаемое функцией значение, все еще ее использует. Рассмотрим следующую некорректную версию предыдущей программы.
// Ошибка, генерируемая при возвращении объекта функцией.
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
class sample {
char *s;
public:
sample() { s = 0; }
~sample() {
if(s) delete [] s;
cout << "Освобождение s-памяти.\n";
}
void show() { cout << s << "\n"; }
void set(char *str);
};
// Загрузка строки.
void sample::set(char *str)
{
s = new char[strlen(str)+1];
strcpy(s, str);
}
// Эта функция возвращает объект типа sample.
sample input()
{
char instr[80];
sample str;
cout << "Введите строку: ";
cin >> instr;
str.set(instr);
return str;
}
int main()
{
sample ob;
// Присваиваем объект, возвращаемый
// функцией input(), объекту ob.
ob = input(); // Эта инструкция генерирует ошибку!!!!
ob.show(); // Отображение "мусора".
return 0;
}
Результаты выполнения этой программы выглядят таким образом.
Введите строку: Привет
Освобождение s-памяти.
Освобождение s-памяти.
Здесь мусор
Освобождение s-памяти.
Обратите внимание на то, что деструктор класса sample вызывается три раза! В первый раз он вызывается при выходе локального объекта str из области видимости в момент возвращения из функции input(). Второй вызов деструктора ~sample() происходит тогда, когда разрушается временный объект, возвращаемый функцией input(). Когда функция возвращает объект, автоматически генерируется невидимый (для вас) временный объект, который хранит возвращаемое значение. В данном случае этот объект просто представляет собой побитовую копию объекта str, который является значением, возвращаемым из функции. Следовательно, после возвращения из функции выполняется деструктор временного объекта. Поскольку область памяти, выделенная для хранения строки, вводимой пользователем, уже была освобождена (причем дважды!), при вызове функции show() на экран выведется "мусор". (Вы можете не увидеть вывод на экран "мусора". Это зависит от того, как ваш компилятор реализует динамическое выделение памяти. Однако ошибка все равно здесь присутствует.) Наконец, по завершении программы вызывается деструктор объекта ob (в функции main()). Ситуация здесь осложняется тем, что при первом вызове деструктора освобождается память, выделенная для хранения строки, получаемой функцией input(). Таким образом, само по себе плохо не только то, что остальные два обращения к деструктору класса sample попытаются освободить уже освобожденную область динамически выделяемой памяти, но они также могут разрушить систему динамического распределения памяти.