Главная » C++ энциклопедия » С » Синтаксис и семантика присваивания
Категория: C++ энциклопедия » С
  • 0

15 дек 2011

Автор: admin

Для присваивания одного объекта другому используется оператор =.

Foo f; 
Foo f1;
f1 = f;


Присваивание выполняется в третьей строке. Если бы f и f1 были целыми или чем-нибудь столь же простым, смысл этой строки был бы предельно ясен: содержимое области памяти, на которую ссылается f, копируется в область памяти, на которую ссылается f1. Только и всего. Но если Foo
относится к нетривиальному классу, в C++ все заметно усложняется. В приведенном примере компилятор предоставляет оператор = по умолчанию, который вызывается для выполнения фактического копирования. Как и с конструкторами копий, вы можете спокойно сидеть и смотреть, как компилятор вкалывает за вас, или написать свой собственный оператор =. То, что делает версия по умолчанию, вам может и не понравиться, особенно в момент освобождения памяти деструктором класса.

class String { 
private:
char* s;
public:
String(char*);
~String();
  void Dump(ostream& os);
};
String::String(char* str) : s(NULL)
{
  if (str == NULL) {   // NULL означает пустую строку
    s = new char[1];
    *s = ‘\0’;
}
else {  
    s = new char[strlen(str) + 1];
  strcpy(s, s tr);
}
}
String::~String()
{
delete s;
}
void String::Dump(ostream& os)
{
  os << “\”” << s << “\””;
}
String* s1 = new String(“Hello”);
String* s2 = new String(“Goodbye”);
s2 = s1;
delete s1;    // Память освободилась, вроде все нормально...
s2->Dump();   // О блом! Ха-ха-ха!
delete s2;    // Помогите, убивают! Ха-ха-ха!


По умолчанию компилятор копирует содержимое s2->s поверх содержимого s1->s. При этом копируется значение указателя, а не символы, поэтому после присваивания возникают две большие проблемы. Два разных объекта ссылаются на одну область памяти, и никто не ссылается на копию Goodbye, созданную командой String* s2 = new String( "Goodbye");. Дальше — больше; при удалении s1 деструктор освобождает область памяти, на которую ссылается s1. Однако на эту память продолжает ссылаться указатель s2->s. Попытка вывести s2->s дает совершенно безумные результаты. «Комедия ошибок» достигает кульминации при попытке удалить s2, поскольку менеджер памяти попытается освободить ранее освобожденную область. Чего только не бывает в C++!

Разумеется, та же проблема возникает и при создании копий. Конструктор копий по умолчанию копирует указатель, а не данные, на которые он ссылается. По этой причине конструктор копий и оператор = обычно перегружаются одновременно.
Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.