Зачем отключать конструктор копирования CObject и присваивание - PullRequest
8 голосов
/ 21 июня 2010

Конструктор копирования и назначение корневого объекта MFC CObject по умолчанию отключены.

  • В MSDN есть описание

Стандартный конструктор копирования класса C ++ по умолчанию выполняет копирование по элементам.Наличие закрытого конструктора копии CObject гарантирует сообщение об ошибке компилятора, если конструктор копирования вашего класса необходим, но недоступен.Поэтому вы должны предоставить конструктор копирования, если ваш класс требует этой возможности.

  • В исходном коде CObject есть комментарий:

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

Мой вопрос: в чем проблема с побитовой передачей по умолчанию?конструктор битовой копии для этого класса CObject?На мой взгляд, было бы лучше дать нам конструктор копирования по умолчанию, и мы могли бы предоставить его при необходимости (глубокая копия)

Ответы [ 2 ]

6 голосов
/ 21 июня 2010

Конструктор копирования по умолчанию является член за элементом, а не поразрядным.

Большинство производных от CObject классов содержат - и управляют напрямую - некоторыми системными ресурсами, у которых нет подсчета ссылок или аналогичного механизма, поэтому выбор, вероятно, был сделан с учетом варианта использования по умолчанию.

например. CGDIObject - это примерно:

class CGDIObject : public CObject
{
    HGDIOBJ m_handle;

    CGDIObject() : m_handle(0) {}
    // derived classes provide a create, attach etc.
   ~CGDIObject() { DeleteObject(m_handle); } 
}

Конструктор копирования по умолчанию здесь был бы опасен (приводил к двойному уничтожению), поэтому обеспечение «правильного» конструктора копирования на удивление сложно и дорого.

Другая причина может заключаться в том, что большинство производных от CObject классов предназначены для мутации и, следовательно, для передачи по ссылке. Отсутствующий конструктор копии будет перехватывать непреднамеренные копии, которые изменяют копию, а не переданный объект:

class CMyObject : public CObject
{
   public:
      AttachFoo(FooHandle foo) { ... }
      AddBar() { ... }
};

bool InitMySession(CMyObject & obj)
{
    obj.AttachFoo(CreateRawFoo());   
    obj.AddBar();
    obj.AddBar();
}

// ...
CMyObj mo;
InitMySession(mo);

Пропуск "&" дает вам код, который хорошо компилируется, но создает временную копию, изменяет ее, а затем удаляет ее, в то время как mo остается неизменной.

Довольно много API следуют этому шаблону, поскольку MFC не полагается на исключения для обработки ошибок (по историческим причинам: не все целевые компиляторы хорошо их поддерживали, и MFC требует много дополнительной обработки ресурсов, которая становится болезненной из-за исключений) ,


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

Решение соответствует «образу мышления» МФЦ и требованиям / ограничениям времени создания МФЦ.

3 голосов
/ 21 июня 2010

Рассмотрим следующее:

class CMyHandle : public CObject
{
    HANDLE hWin32;
public:
    CMyHandle()
    {
        hWin32 = SomeFunctionThatMakesHandle();
    }
    ~CMyHandle()
    {
        CloseHandle(hWin32);
    }
};

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

Поскольку большое количество классов MFC управляют дескрипторами, имеет смысл заставить создателя класса явно переопределить для создания конструкторов копирования и операторов назначения копирования.

РЕДАКТИРОВАТЬ: Например:

int main()
{
    CMyHandle h1; //CMyHandle's constructor initializes the handle
    {
        CMyHandle h2(h1); //Memberwise copy into h2. In this case, it copies the
                          //handle
    } //h2 destroyed, closes handle
    //h1 is now invalid (because the underlying handle was closed)!
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...