在声明变量时引用同一变量

11

在处理C++代码时,我几次看到了以下类型错误:

QString str = str.toUpper();

这是一个相当容易犯的错误,但它仍然可以编译和执行(有时会崩溃,有时不会)。我无法想象在任何情况下,这都是你实际想要做的事情。

一些测试表明,调用的是复制构造函数而不是默认构造函数,并且对象正在从复制构造函数内部被赋予自身。

是否有人能够解释为什么这不是编译器错误,甚至不是警告?


1
这被指定为未定义行为(不需要诊断),可能是因为存在一种或多种这种代码实例,对其进行诊断会过于复杂。 - Mark B
可能是因为编译器不知道 toUpper() 返回相同的实例?我可以想象编译器编写者很难检查这一点。 - Karel Petranek
@MarkB:这是定义行为,请参考我的答案。 - Daniel
2个回答

7

在等号出现时,对象str已经被定义,因此可以在该点使用。

错误在于试图用自身初始化对象,编译器允许警告(如果它能够检测到)。然而,在每种情况下都无法进行检测,因此编译器不是必需的。

例如,如果int f(const int&)不使用其参数的值,则int x = f(x);是完全正确的。如果编译器尚未看到函数体,它如何知道呢?


1
那很有道理。我认为出于正常情况的考虑(如果没有其他原因),即使在尚未构造 x 的情况下调用 f(x) 仍应该是一个错误,因为正如你所提到的,唯一安全的情况就是函数不使用它。 - Chris
值得注意的是,当对象通过“auto”关键字定义时,此语法确实被禁止,但出于类型推断的原因。“auto x = x + 1;”是无效的,符合规范的编译器应该拒绝它。 - Michael Price
@Chris - 实际上可以保存指向对象的指针或引用,并稍后使用它。只是不能使用值(因为还没有值)。C和C++以不禁止仅仅是有些偏远有用的事情而闻名。 - Bo Persson
那么在等号处,x的状态到底是什么?哪个构造函数在那时被调用了? - Kerrek SB
一个常见的用法是将 this 传递给基类构造函数……它看起来不同,但最终结果是相同的。 - Dennis Zickefoose
显示剩余8条评论

-4

没有错误或警告,因为它等同于:

QString str;
str = str.toUpper();

就像这样

QString str = "aaa";

等同于

QString str;
str = "aaa";

要在同一语句中完成这个操作,你需要使用构造函数,但这样做是无法编译通过的:

QString str(str.toUpper());

就像这样:

QString str("aaa");

不等于

QString str;
str = "aaa";

4
这句话的意思是:“QString str; str = str.toUpper();QString str = "aaa"; 并不等同,就像后者并没有调用赋值运算符一样。” - Mark B
QString str = "aaa";QString str; std = "aaa" 实际上是一样的吗?我不是 C++ 专家,但在我看来,第一个调用了构造函数,而第二个则调用了默认构造函数和 operator=Codepad 似乎也是这么认为的。 - user395760
QString str = "aaa" 不会调用默认构造函数。它将调用一个接受 const char* 的构造函数,而该构造函数的参数将是 "aaa"。也就是说,这与默认构造 QString 然后进行复制赋值不同。 - Nicol Bolas
@NicolBolas:它还将调用复制构造函数。该调用可以省略,但是,无论实际调用是否省略,语法QString str =“aaa”都需要一个可访问的复制构造函数。 - Armen Tsirunyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接