这个拷贝构造函数有什么问题?

时间:2010-08-06 01:02:08

标签: c++ tree copy-constructor

我一直在尝试为树提出一个复制构造函数。我找到了不少建议。

这个让我感兴趣。

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网站。

4 个答案:

答案 0 :(得分: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 ++构造函数。这样,编译器和你在复制对象时就在同一页面上,而且其他程序员会发现它更容易跟踪你的代码。

答案 1 :(得分:3)

我不会将方法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;
         ...
      }

通过实现复制构造函数,您还可以根据需要在深拷贝和浅拷贝之间进行混合。

答案 2 :(得分:0)

已经有一段时间但if()正在检查分配是否为非空。 IE“新”成功了。

答案 3 :(得分:0)

  

if (TreeNode* tmp = new TreeNode)是什么意思?

这应该检查分配的结果,即。它没有失败。但是,这是一种不好的方法,因为:

  1. 正如其他人所指出的那样,new TreeNode将在新的C ++编译器中引发异常
  2. 即使它没有抛出异常,也很糟糕:当只有部分节点无法分配时,clone()的调用者不会注意到任何东西,但会默默地只获取一部分树。
  3. 在考虑标准行为时,此方法异常不安全。