Что не так с этим конструктором копирования? - PullRequest
4 голосов
/ 06 августа 2010

Я пытался придумать конструктор копирования для дерева.Я нашел довольно много предложений.

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

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)?"это?

Приведенный выше пример взят с этого сайта.

Ответы [ 4 ]

10 голосов
/ 06 августа 2010

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

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

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

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

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

3 голосов
/ 06 августа 2010

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

Реализуйте конструктор копирования в C ++ следующим образом (я оставил все остальные члены для его краткости):

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

Редактировать: Данный пример реализует / предлагает поверхностную копию.Это то, что компилятор создает для вас, если вы не реализовали конструктор копирования.Так что, если вы довольны мелкой копией, вы можете не использовать конструктор копирования.

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

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

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

0 голосов
/ 06 августа 2010

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

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

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

Прошло некоторое время, но if () проверяет, является ли распределение ненулевым. То есть "новое" получилось.

...