临时变量能否绑定到非const引用?

5
我编写了以下代码来进行测试:
struct X
{
   char* x;
   X()
   {
      x = new char('a');
   }
   ~X()
   {
      *x = 'b';
      delete x;
   }
};

void foo(const X& x)
{
}
void goo(X& x)
{
}

int main()
{
   foo(X());
   goo(X());
}

临时变量的析构函数在两个函数退出后才被调用,但我认为只有将临时变量绑定到const引用才可以。那么为什么goo能够工作呢?

这是未定义行为吗?是MSVS错了还是没问题的?


如果是未定义行为,那么根据定义,MSVS 不能出错。因为未定义行为的表现包括“一切都按预期工作”(对于“预期”的每个值)。 - Matteo Italia
这是另一个问题的重复。是的,MSVC在这里有点淘气,请查看ideone:http://ideone.com/zykx9。 - Pubby
1
可能是为什么非const引用不能绑定到临时对象?的重复问题。 - iammilind
1
如果您将警告级别设置为4,则应该收到此类警告:“使用非标准扩展:'argument':从'X'转换为'X&'”。 - Jagannath
1
如果将“禁用语言扩展”设置为“是”,则在MSVC2010中会出现错误。配置属性-> C / C ++->“语言->禁用语言扩展”=是。 - Jagannath
2个回答

3

这是非法的。符合规范的实现会对其进行诊断(即至少警告),但MSVC++允许其作为扩展。

如果您不太友好,也可以将其视为错误,但我记得他们仍然允许它的原因是因为长期遗留原因:名义上支持在C++标准化之前为MSVC ++编写的代码,当然一旦您允许人们编写此代码,他们也会在新代码中意外编写,所以遗留问题就会存在。如果这是有意的,那么它就是(误)功能,而不是错误,对吧?无论如何,符合规范的实现都需要诊断格式错误的程序,因此如果没有收到警告,则编译器不符合规范。


我不喜欢“bug”这个词,因为“error”是一个更准确的词。如果这是故意的,那么它就不是一个错误,至少不是一个编程错误。(支持它的决定是一个错误,因为禁止绑定到非const引用的规则早在第一款MS C++编译器出现之前就已经存在了至少5年。当MS推出他们的第一个C++编译器时,CFront已经警告在这种情况下使用过时的功能。) - James Kanze
@James:考虑到微软一贯的“拥抱和扩展”标准方法,我可以想象他们会给一个“规则”在标准之前多少重视。毕竟,Bjarne认为自己是语言的发明者还是什么?;-) - Steve Jessop
1
请注意,至少对于VS2008而言,VS将为使用任何编译器扩展(包括此扩展)发出警告。甚至有一个编译器开关可以关闭它们。就像GCC一样。因此,如果您要指责微软在这方面进行“拥抱和扩展”,那么我们不应该包括一些项目无法编译的无数GCC扩展吗? - Nicol Bolas
@Nicol:我并不是在指责微软做了什么,我只是说如果它没有警告,那么它就不符合规范。如果它有警告,那就太好了,尽管我怀疑 OP 由于某种原因没有看到警告。司法部指控微软“拥抱和扩展”是基于其高管的言行证词。但我只是半认真地说:我的观点只是詹姆斯称这是 C++ 的规则,事实上微软将会按照自己的意愿进行 C++ 实现,特别是在标准之前。 - Steve Jessop
顺便说一下,我会(也确实会)指责大多数编译器默认选项下的非兼容性问题。没有至少--warn-pedantic选项,GCC在检测程序错误方面也不符合要求,尽管我不认为它具有任何选项的特定扩展功能。这是否可以与GNU的更广泛的“采纳和扩展”策略有关是一种纯粹的暗示;-) - Steve Jessop

1

这显然是一个微软的扩展。例如,在GCC 4.3.4中,它无法编译,并显示以下消息:

prog.cpp: In function ‘int main()’:
prog.cpp:25: error: invalid initialization of non-const reference of type ‘X&’ from a temporary of type ‘X’
prog.cpp:18: error: in passing argument 1 of ‘void goo(X&)’

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