2010-08-06 6 views
4

Я пытался создать конструктор для дерева. Я нашел немало советов.Что случилось с этим конструктором копирования?

Это меня заинтересовало.

class TreeNode 
{ 
    int ascii; 
    TreeNode* left; 
    TreeNode* right; 

public: 
    TreeNode() { ascii = 0; left = right = 0; } 
    TreeNode* clone(); 
    // ... 
}; 

TreeNode* TreeNode::clone() 
    { 
     if (TreeNode* tmp = new TreeNode) 
     { 
      tmp->ascii = ascii; 
      if (left) tmp->left = left->clone(); 
      if (right) tmp->right = right->clone(); 
      return tmp; 
     } 
     return 0; 
    } 

Что "if (TreeNode* tmp = new TreeNode) означает?

Другое, чем это выглядит хорошо. Это просто не работает очень хорошо.

Любая идея, что случилось с ним?

В примере выше было получено от this.

+2

Оператор 'if' проверяет, что распределение выполнено успешно, поскольку с момента появления исключений больше не требуется в C++. Смотрите: http://www.freshsources.com/Except2/ALLISON.HTM –

+0

Обратите внимание, что конструктор копирования для вашего класса будет иметь подпись типа «TreeNode (const TreeNode & source)», и вы будете работать непосредственно над новым объектом , как и в любом другом конструкторе. См. Ответ Джона. –

+1

Это тоже выглядит хорошо. В какой моде он работает не очень хорошо? Как указывали другие, это реализует метод клонирования, а не конструктор копирования. Это проблема? Вы пытаетесь использовать класс, как если бы у него был конструктор копирования? Он имеет значение по умолчанию, а значение по умолчанию для этого класса неверно. – Omnifarious

ответ

10

Ну, для начала он не является конструктором копирования - конструкторы копирования имеют очень четко определенный синтаксис в C++, поэтому у соответствующего конструктора копии будет прототип TreeNode(TreeNode const &). Просто, чтобы получить правильность терминологии (и компилятор все равно будет генерировать конструктор копирования, поскольку он не знает, что должна делать функция clone()).

Выражение в выражении if будет выделять новый объект TreeNode и будет иметь целью проверить, что распределение выполнено успешно (путем проверки того, что результирующий указатель не равен 0). К сожалению, это предстандартные C++ и современные реализаций C++, которые стандартно соответствуют, вместо этого генерируют исключение std::bad_alloc, поэтому тест будет в основном давать пользователю теплые нечеткие ощущения, что что-то происходит с отказом выделения памяти, даже если это не так.

Для того чтобы код работал должным образом на стандартном компиляторе, вам придется использовать nothrow new. Из памяти линия будет читать что-то вроде этого:

if (TreeNode* tmp = new(std::nothrow) TreeNode) 

Все, что сказал, если TreeNode не является частью иерархии объектов, опирающейся на наличие функции clone() я покончила бы с ним и осуществить ++ конструктор собственно C вместо. Таким образом, компилятор, и вы находитесь на одной странице, когда речь заходит о дублировании объектов, а также другие программисты будут немного легче следовать вашему коду.

0

Это было какое-то время, но if() проверяет, не является ли выделение ненулевым. IE "новый" удалось.

3

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

Реализовать конструктор копирования в C++, как это (я ушел из всех остальных членов, чтобы держать его в короткий):

class TreeNode { 
    public: 
     TreeNode(const TreeNode& source) { 
      // copy members here, e.g. 
      left = source.left; 
      ... 
     } 
}; 

Edit: пример, приведенный инвентарь/указывает на неполную копию. Это то, что создает компилятор для вас, если вы не реализовали конструктор копирования. Поэтому, если вы довольны мелкой копией, вы можете также оставить конструктор копии.

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

class TreeNode { 
    public: 
     TreeNode(const TreeNode& source) { 
     left = source.left != NULL ? new TreeNode(*source.left) : NULL; 
     ... 
     } 

Реализуя конструктор копирования можно также смешивать между глубокой копии и неглубоко-копии в случае необходимости.

+1

Копирование конструкторов в C++ должно всегда глубоко копироваться. –

+0

Это плохая копия-ctor, так как она испортила собственность (в основном это эквивалентно тому, что делает компилятор для вас). Имея 'clone()', вы должны сделать 'left = source.left-> clone()', аналогично для 'right'. – jpalecek

+0

@ Даниэль: Я думаю, что вы хотите, чтобы глубокая копия зависела от ваших требований. @jpalecek: Да, вы правы. Однако, перегружая конструктор копирования, вы можете выбирать между мелкой копией (что делает компилятор) и глубокой копией (что вам может понадобиться). Также вы можете выбирать между этими параметрами. @both: Я обновлю свой ответ, чтобы отразить ваши комментарии. Спасибо за обоих! – Manfred

0

Что означает if (TreeNode* tmp = new TreeNode)?

Это должно проверять исход распределения, т.е. что он не потерпел неудачу. Тем не менее, это плохой способ сделать это, потому что:

  1. , как другие отметили, new TreeNode сгенерирует исключение в новых компиляторов C++
  2. Даже если бы не бросили исключение, это плохо: когда только некоторые из узлов не могут выделяться, вызывающий абонент clone() ничего не заметил, но будет тихо получать только часть дерева.
  3. При рассмотрении стандартного поведения этот метод является исключением-небезопасным.