2010-09-28 87 views
2

我目前正在为链接列表类实现一个复制构造函数。当我使用另一个链接列表作为参数创建类的新实例时,正在为我作为参数传递的对象调用构造函数。这让我难以置信。下面是部分有必要了解这是怎么回事的主要方法:在错误的对象上调用复制构造函数

int main() 
{ 
    LinkedList ll; 
    LinkedList ll2(ll); 
} 

所以,与其呼吁[112拷贝构造函数,用于LL拷贝构造函数被调用。在我试图将ll复制到一个新的LinkedList中之前,我已经确认ll的大小是正确的3,即ll2。拷贝后,两者的大小相同,大于3,但更奇怪的是,ll的拷贝构造函数被调用,而不是ll2的拷贝构造函数。由于我使用的是VC++,因此我已经通过该程序来确认这一点。

下面是LinkedList类的拷贝构造函数:

LinkedList::LinkedList(const LinkedList & other)   
{ 
    LLNode *otherCurNode = other.GetFirst(); 
    if (otherCurNode != NULL) 
    { 
     front = new LLNode(otherCurNode->GetValue(), NULL, NULL); 
     back = front; 
    } 
    else 
    { 
     front = NULL; 
     back = NULL; 
    } 
    LLNode *curNode = front; 
    while (otherCurNode != NULL) 
    { 
     Insert(otherCurNode->GetValue(), curNode); 
     curNode = curNode->GetNext(); 
     otherCurNode = otherCurNode->GetNext(); 
     back = curNode; 
    } 
    numNodes = other.GetSize(); 
} 

我的道歉,如果这最终是一个简单的问题 - 我是相当新的C++。任何帮助将不胜感激!

+1

从你显示的代码中,第一行应该为'll'调用一个拷贝,第二行为'll2'。你如何确定哪个副本被调用?您是否可以将您的代码缩减为一个简单的,自包含的代码片段,该代码片段展现您认为您所看到的行为?很可能,将代码拷贝到这样的代码片段中,你会发现你的问题。如果不是的话,你有一段完美的代码可以回到这里,并询问(一个新问题)。 – sbi 2010-09-28 05:37:27

+0

WOW。我遵循你的建议,并慢慢地将一些片段添加到一个非常基本的程序中来复制功能。然后,我再次回到我的程序上工作,Voila,问题消失了。由于我不记得修改任何代码至少一个小时,所以我没有想到我做了什么,但是我要撤消一些最近的更改,以查看我是否无法弄清楚什么是导致它... – AndyPerfect 2010-09-28 06:41:18

+0

所以我发现了什么问题。我的结构如下:LinkedList.h包含类声明,LinkedList.cpp包含类中包含的所有方法的实现。 TestCases.cpp包含LinkedList.h。但是,我在LinkedList.cpp中声明了LinkedList的类变量,而不是我的头文件。我可以在三个小时看完之后向你保证,我不会再犯这个错误了。再次感谢你们所有的答案!你的答案帮我搞定了全部数字=) – AndyPerfect 2010-09-28 06:48:23

回答

7
LinkedList ll = LinkedList(); 

这创建一个链表实例,然后这个实例被复制构造。这看起来像Java或C#主义。它实际上是等同于:

LinkedList ll(LinkedList()); 

要创建一个空的链表,简单的写:

LinkedList ll; 

这将隐式调用默认的构造函数。

此外,请确保您有一个默认的构造函数,将链表正确初始化为空。如果你没有一个,那么这个列表的变量将以堆栈中的垃圾值结束。

+0

我想这是我的Java/VB/C#闪耀通过=)。我修复了我原来的代码,但问题仍然存在。 – AndyPerfect 2010-09-28 03:55:44

+5

不,不要添加括号来显式调用构造函数。对于不带参数的构造函数,它将被解释为函数声明。 – jamesdlin 2010-09-28 03:56:15

+0

@jamesdlin好点。我正要添加一个关于'typename'关键字的注释,但是真的更好,我只是完全删除了这个句子。 – 2010-09-28 03:58:54

2

奇怪的事情往往是不正确的内存处理的迹象。我可以看到您发布的代码的一个直接问题,其他功能中可能存在类似的问题。

就行while (otherCurNode->GetNext() != NULL),如果otherCurNode已经是NULL,就会发生坏事。当另一个列表为空时以及在通过otherCurNode = otherCurNode->GetNext();到达列表末尾时都是如此。你真的想要它while (otherCurNode != NULL)

+0

可以理解。我认识到这是一个问题,但实际上并没有解决手头真正的问题,因为错误对象的构造函数被调用。感谢您的提示,虽然=) – AndyPerfect 2010-09-28 04:09:14

1

因此,不是调用ll2的复制构造函数,而是调用ll的复制构造函数,并将ll2设置为与ll相同的引用。

您可以确定这不是发生了什么事。您的llll2变量(顺便说一句,您可以看到为什么在短名称中使用小写字母l从来不是一个好主意)分配在堆栈上,它们不是引用。要查看此信息,请在两个变量都在范围内时打开快速监视,然后键入&ll,然后输入&ll2。你会看到他们有不同的地址。

你的默认构造函数和赋值运算符是什么样的?还有其他的构造函数吗?任何其他你指定front实例变量的地方?

+0

的确,我已检查并确保ll和ll2位于内存中的不同位置。有趣的是,这两个值都指向内存中的相同位置... 在行LinkedList ll2(ll)期间修改了ll的front的位置;这整个情况让我感到困惑。 – AndyPerfect 2010-09-28 04:32:55

+0

看起来您已将您的赋值运算符作为默认值,该值由编译器自动生成。它分配所有成员,包括'front'。这不是你想要的行为。 – 2010-09-28 05:35:38

+0

规则是,如果你实现自定义拷贝构造函数,那么也要实现赋值操作符。 – 2010-09-28 05:36:15