2015-07-18 1 views
0

У меня есть «витая» вопрос ... Пусть иметь класс какC++ удалить/деструктор безопасный вызов

class MyClass { 
public: 
MyClass(); 
~MyClass(); 
MyClass& operator=(const MyClass& obj); 
private: 
    int* mem; 
}; 

, где в основном MyClass inits как-то memnew вызова), то ~MyClass()mem освобождает с оператором delete. Пусть, кроме того, оператор = перегружен с кодом

MyClass& operator=(const MyClass& obj) { 
if(this != &obj) { 
    //allocate memory of "this" with the "new" operator and copy "obj" data; 
} 
return *this; 
} 

мой вопрос в основном следующее ... С следующей последовательности операторов

//statement 1 for short 
MyClass my_obj = some_obj_of_MyClass; 

я предполагаю, что все в порядке, так как оператор = выделяет памяти и копирует данные, но со следующими данными:

//statement 2 for short 
MyClass obj; //allocate memory for "mem" 
obj = some_obj_of_MyClass; 

если вы считаете, что это не так t исправить реализацию, которую я предложил, поскольку я не удаляю выделенную память раньше. Я мог бы вызвать деструктор внутри блока оператора присваивания, но в этом случае, вероятно, утверждение 1 не было бы безопасным.

Так что это безопасный способ реализовать все? Я предполагаю, что проблема здесь заключается в том, чтобы понять, когда вызывается деструктор или как его правильно реализовать.

+2

В вашем первом примере используется конструктор копирования, а не 'operator ='. В 'operator =' гарантируется, что 'this' относится к уже построенному объекту. – melpomene

+2

'// statement 1' запускает конструктор копирования (сгенерированный компилятором), * не * a (определяемый пользователем) оператор присваивания. Он просто установит 'my_obj.mem' то же значение, что и' some_obj_of_MyClass.mem', поэтому у вас будет два объекта, указывающих на одну и ту же память, и, в конечном счете, на двойное разрушение. Так что нет, это не нормально. См. Также: [Правило три] (https://en.wikipedia.org/wiki/Rule_of_three_ (C% 2B% 2B_programming)) –

+0

Является ли выражение '// 1 эквивалентом' MyClass obj (some_obj_of_MyClass) '? – user8469759

ответ

0

Ваш код нарушает правило трех: Всякий раз, когда класс предоставляет пользовательский

  1. конструктор копирования
  2. оператор копирующего присваивания
  3. деструктор

он должен, вероятно, предоставить все три. Поскольку, если какой-либо из них опущен, можно построить варианты использования, в которых происходят плохие вещи. Например, вопреки интуиции, заявление

MyClass my_obj = some_obj_of_MyClass; 

не вызывает оператора присваивания. Он вызывает конструктор копирования, который вы не предоставили. Таким образом используется конструктор копирования по умолчанию, который просто копирует указатель. Как только my_obj или some_obj_of_MyClass будет разрушен, другой будет иметь указатель на область удаленной памяти.

С другой стороны, операторы

MyClass obj; 
obj = some_obj_of_MyClass; 

будет первым по умолчанию построить obj, а затем вызвать оператор присваивания на нем. Оператор присваивания должен быть записан таким образом, чтобы он работал правильно во всех возможных состояниях obj (то есть он не должен течь из памяти или двойной памяти удаления). То есть, если выделено obj.mem, оператор присваивания должен либо повторно использовать эту память, либо освободить ее (возможно, заменив ее новым распределением). Если obj.mem может быть нулевым указателем, то оператор присваивания должен включать специальную обработку этого специального случая.

Итак, ваш выбор в основном заключается в том, хотите ли вы, чтобы указатель mem стал нулевым указателем. Если вы этого не допускаете, ваш конструктор по умолчанию должен выделять область фиктивной памяти, которая может быть освобождена оператором присваивания ,

Вы также можете работать над правилом три, удалив нереализованные функции. Ваш класс может быть объявлен как это:

class MyClass { 
public: 
    MyClass(); 
    MyClass(const MyClass&) = delete; 
    MyClass& operator=(const MyClass& obj); 
    ~MyClass(); 
private: 
    int* mem; 
}; 

Это запретит заявление

MyClass my_obj = some_obj_of_MyClass; 

принуждая код пользователя, чтобы использовать более многословным

MyClass obj; 
obj = some_obj_of_MyClass; 

но что делает реализацию MyClass в бит проще.

 Смежные вопросы

  • Нет связанных вопросов^_^