2010-04-25 88 views
4

假设我有:复制构造,为什么在按值函数的返回

class A 
{ 
    A(A& foo){ ..... } 
    A& operator=(const A& p) { } 
} 

... 
A lol; 
... 

A wow(...) 
{ 

    return lol; 
} 

... 
... 
A stick; 
stick = wow(...); 

然后,我将在最后一行得到一个编译错误。但是如果我在'A &'之前加上'const',那就OK了。

我想知道为什么。问题究竟在哪里? 我不明白为什么它应该是const。

语言:C++

我编辑...我认为,改变它的相关性。这给了错误。

+0

您可能想要添加您正在谈论的语言。 – 2010-04-25 07:49:41

+0

C++ ............ – fsdfa 2010-04-25 07:50:19

+1

好吧,现在看起来问题比看起来更复杂一些(几个删除的答案会显示),为什么你不改变你的代码到一些完全可编译的,除了你看到的错误,并陈述你正在使用的确切的编译器版本。上面的代码不能代表你的代码。 Fors先生,'A'中没有什么是'公共'的。) – sbi 2010-04-25 08:24:07

回答

0

不可复制。您是否缺少默认构造函数,或者忘记了构造函数public

请参阅http://www.ideone.com/nPsHj

(注意,一个拷贝构造可以采取cv A&参数与任何常量挥发性组合加上一些默认参数。参见§ [class.copy]/2在C++标准。)


编辑:有趣,克++ - 4.3(ideone)和4.5(具有-pedantic标志)没有编译错误,但克++ - 4.2会抱怨:

x.cpp: In function ‘int main()’: 
x.cpp:19: error: no matching function for call to ‘A::A(A)’ 
x.cpp:7: note: candidates are: A::A(A&) 
+0

我猜GCC有其他标准。 – fsdfa 2010-04-25 08:07:28

+0

@fsdfa:你使用哪个编译器(和版本)? – kennytm 2010-04-25 08:08:42

+0

3.4.5 MINGW。有和没有迂腐我有错误。 我不知道mingw版本和其他版本之间的对应关系。 Intresiting ...也许它是唯一的编译,强制它作为一个良好的编码实践。 我正是那个错误 – fsdfa 2010-04-25 08:12:06

1

下面的代码编译PERF ectly精细既Comeau和VC9:

class A 
{ 
public: 
    A() {} 
    A(A&){} 
}; 

A lol; 

A wow() 
{ 
    return lol; 
} 

int main() 
{ 
    A stick; 
    stick = wow(); 
    return 0; 
} 

如果这不符合你的编译器编译,然后我怀疑你的编译器被打破。如果是这样,那么这意味着你应该粘贴真实的代码,而不是提供一个与你看到的问题不相似的代码片段。

+0

为什么不呢?它是有道理的,但我不认为这是必要的。 – fsdfa 2010-04-25 07:57:12

+0

它在调用函数返回时调用的copyconstructor,它的另一个事物(实际上,我用const覆盖它) – fsdfa 2010-04-25 08:01:36

+0

'哇'将'lol'复制到它的返回值中。然后通过您的赋值操作符将返回值分配给'stick'。赋值运算符接受const引用,所以它不介意你提供了一个r值。 – 2010-04-25 08:42:40

1

wow的调用会产生一个临时对象,一个r值。 R值不能分配给非常量参考。由于您的拷贝构造函数接受非const引用,因此无法将调用结果直接传递给wow。这就是为什么加入const解决了问题。现在复制构造函数接受const引用,这些r值绑定到很好。

机会是,你的拷贝构造函数不会改变它拷贝的对象,所以参数应该被const-reference传递。这是复制构造函数如何工作,除非在特定的文档化情况下。

但是,正如sbi在他的回答中指出的,这个拷贝构造函数不应该被调用。所以虽然这是真的,但它可能与你的问题无关。除非有编译器错误。也许你的编译器会看到两步构造,并决定将A stick; stick = wow();转换为A stick = wow();,从而将中间人剪掉。但是这会是一个错误,正如它产生的编译错误超出完全合法的代码一样。但是如果没有实际的代码,就不可能说出真正发生的事情。在你的拷贝构造函数出现任何问题之前,应该有其他几个错误。

+0

这就是我首先想到的。但考虑到'一根棍子; stick = wow(...);',为什么在wow()调用的_caller's_端调用该副本? – sbi 2010-04-25 08:17:49

+0

是的,我只是注意到了自己,并且正在编辑我的答案。 – 2010-04-25 08:30:46

+0

...和你一样卡住了,就像我一样。 ':)' – sbi 2010-04-26 15:28:39

0

此功能:

A wow(...) 
{ ... } 

由值返回的对象。
这意味着它被复制回调用函数的地方。

这条线:

stick = wow(...); 

上是否粘副本建设。
复制到棒中的值是从函数wow()中复制的值。
但请记住,调用wow()的结果是一个临时对象(它从wow()中复制回来,但不在变量中)。

所以,现在我们就来看看拷贝构造函数对于A:

A(A& foo){ ..... } 

您正在尝试一个临时对象传递给一个参考参数。这是不允许的。一个临时对象只能绑定到一个const引用。有两种解决方案:

1)使用const引用。
2)按值传递给拷贝构造函数。

不幸的是,如果你使用解决方案(2),你会有点卡住,因为它成为一个循环依赖。按值传递涉及使用复制构造函数,以便输入一个无限循环。所以你的解决方案是使用const引用传递。

+0

@Martin:'stick = wow(...);'在'stick'上做__assignment__,而不是复制构造。 (我也遇到了这个陷阱。) – sbi 2010-04-25 08:26:08

+0

问题中的代码不是fsdfa正在使用的代码,或者它是一个破碎的编译器。看到我的答案:http://stackoverflow.com/questions/2707534/2707542#2707542 – sbi 2010-04-25 08:33:20

相关问题