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)意思?

除此之外,它看起来还不错。它只是不能很好地工作。

知道有什么问题吗?

上面的例子来自这个网站。

4

4 回答 4

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++ 构造函数。这样,在复制对象时,编译器和您在同一页面上,而且其他程序员会发现更容易遵循您的代码。

于 2010-08-06T01:11:44.937 回答
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;
         ...
      }

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

于 2010-08-06T01:07:50.283 回答
0

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

于 2010-08-06T01:05:13.267 回答
0

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

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

  1. 正如其他人指出的那样,new TreeNode将在新的 C++ 编译器中引发异常
  2. 即使它没有抛出异常,也很糟糕:当只有部分节点分配失败时,调用者clone()不会注意到任何事情,而只会默默地获取树的一部分。
  3. 在考虑标准行为时,此方法是异常不安全的。
于 2010-08-06T01:23:29.347 回答