我一直在尝试为树提出一个复制构造函数。我找到了不少建议。
这个让我感兴趣。
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网站。
答案 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)
是什么意思?
这应该检查分配的结果,即。它没有失败。但是,这是一种不好的方法,因为:
new TreeNode
将在新的C ++编译器中引发异常clone()
的调用者不会注意到任何东西,但会默默地只获取一部分树。