Почему деструктор класса вызывается в начале работы с классом? Собственно я ожидал совсем другого поведения вот такой код: Код (Text): /* -- это деструктор в классе -- */ string:: ~string( void ) { delete buf; printf ("destructor\n"); } /*-------------------------------*/ int main(){ int a; string str1, str2; str1 = "some string"; str2 = "another string"; str1.print(); str2.print(); return 0; } выводит на экран следующее: Код (Text): destructor destructor some string another string destructor destructor
str1 = "some string"; случаем, не разворачивается в str1 = string("some string") ? Введи тогда уж отладочные сообщения во все операции, чтобы иметь полную картину. Или смотри ассемблерный листинг.
IceStudent Хочу понять, что к чему, не заглядывая в дизассемблер. Сам класс выглядит так: Код (Text): class string { char *buf; int length; // длина буфера (не строки); public: virtual ~string( void ); string( const char *input_str = "" ); string( const string &r ); virtual const string &operator=( const string &r ); virtual int operator< ( const string &r ) const; virtual int operator> ( const string &r ) const; virtual int operator==( const string &r ) const; virtual void print() const; // ... }; //---------------------------------------------------------------- inline string::string( const char *input_str /* = ""*/ ) { length = strlen(input_str) + 1; buf = new char[ length ]; strcpy( buf, input_str ); printf ("function inline string::string( const char *input_str /* = ""*/ )\n"); printf ("Buffer = %s\n", buf); } //---------------------------------------------------------------- inline string::string( const string &r ) { length = r.length; buf = new char[ length ]; strcpy( buf, r.buf ); printf ("function inline string::string( const string &r )\n"); } //---------------------------------------------------------------- /* виртуальный */ string:: ~string( void ) { delete buf; printf ("function string:: ~string( void )\n"); printf ("Buffer = %s\n", buf); } //---------------------------------------------------------------- /* виртуальный */ const string &string::operator=( const string &r) { if( this != &r ) { if( length != r.length ) { free( buf ); length = r.length; buf = new char[ length ]; } strcpy( buf, r.buf ); } printf ("operator=\n"); return *this; } //---------------------------------------------------------------- /* виртуальный */ int string::operator< ( const string &r ) const { return strcmp(buf, r.buf) < 0; } //---------------------------------------------------------------- /* виртуальный */ int string::operator> ( const string &r ) const { return strcmp(buf, r.buf) > 0; } //---------------------------------------------------------------- /* виртуальный */ int string::operator==( const string &r ) const { return strcmp(buf, r.buf) == 0; } //---------------------------------------------------------------- /* виртуальный */ void string::print() const { printf("%s\n", buf); } а теперь простенький main: Код (Text): int main(){ string str1; str1 = "some string"; return 0; } Этот main последовательно вызывает следующие функции класса и показывает состояние буфера: Код (Text): function inline string::string( const char *input_str /* = ""*/ ) Buffer = function inline string::string( const char *input_str /* = ""*/ ) Buffer = some string operator= function string:: ~string( void ) Buffer = some string function string:: ~string( void ) Buffer = some string Тут у меня вопросы: 1.Откуда берется второй вызов функции inline string::string( const char *input_str /* = ""*/ ), ведь она из функции operator= не вызывается? И как при этом в буфер попала строка "some string"? 2.Почему два раза вызывается деструктор string:: ~string( void )? 3.Для чего нужна функция inline string::string( const string &r ), если у нас есть оператор присваивания?
1. У тебя нет конструктора по-умолчанию (если бы ты вообще не написал ни одного конструктора, он бы был создан неявно, а так его нет), поэтому при объявлении string str1; выывается единственный подходящий: string::string( const char *input_str ) с аргументом по умолчанию - "" отсюда и получаются первые две строчки: function inline string::string( const char *input_str /* = ""*/ ) Buffer = дальше идет: str1 = "some string"; у тебя нет оператора присваивания с аргументом const char*, поэтому единственный путь для компилятора - создать временный объект, используя конструктор string::string( const char *input_str ) и уже его присвоить объекту str1: string tmp("some string"); str1.operator=(tmp); создание неявного объекта и порождает следующие две строки: function inline string::string( const char *input_str /* = ""*/ ) Buffer = some string 2. теперь уже очевидно, почему вызываются два деструктора: один для str, другой для временного объекта кстати, в деструкторе ты выводишь строку по адресу buf после вызова delete buf; в твоем компилере это работает, но в общем случае использование указателя после освобождения указываемой им памяти некорректно 3. конструкторы копирования используются при передаче аргументов функции по значению, а также при возврате значения объектного типа кажется, есть еще и другие случаи, точно не помню
Nouzui Если я правильно понял, для предотвращения создания временного объекта и связанных с эти накладных расходов правильнее будет непосредственно вызвать конструктор при определении объекта? Код (Text): int main{ string str1("another string"); return 0; }
cresta В данном случае можно написать и так: Код (Text): int main{ string str1 = "another string"; return 0; } По определению при конструировании можно указывать и =, и (), и это будет эквивалентно (естественно, если аргумент только один). Ни в том, ни в другом случае временных объектов создаваться не будет.
а проще написать перегружаемый оператор = и для char *. тогда проблема с временным объектом должна отпасть.