一个VS2010错误?允许将非常量引用绑定到右值,甚至没有警告

One VS2010 bug ? Allowing binding non-const reference to rvalue WITHOUT EVEN a warning?

本文关键字:警告 绑定 引用 错误 VS2010 常量 非常 一个      更新时间:2023-10-16
string foo() { return "hello"; }
int main() 
{
    //below should be illegal for binding a non-const (lvalue) reference to a rvalue
    string& tem  = foo();   
    //below should be the correct one as only const reference can be bind to rvalue(most important const)
    const string& constTem = foo();   
}
  1. GCC 是给出编译错误的好方法:从 std::string 类型的临时初始化无效的 std::string& 类型的非 const 引用
  2. VS2008还不错,因为它至少给出了一个编译警告:警告 C4239:使用了非标准扩展:"正在初始化":从 std::stringstd::string & A 非常量的转换引用只能绑定到左值
  3. 有问题的来了 - VS2010(SP1( 没有任何问题错误或警告,为什么??!!我知道VS2010中的右值引用可用于与右值绑定,但我没有使用&&,而是在演示代码中,我只是使用非常量左值引用!

somone可以帮我解释VS2010的行为吗?这是一个错误吗!?谢谢

这是VS编译器的已知问题/功能。他们一直允许这样做,并且似乎没有任何推动删除该扩展名。

编译器将在打开禁用语言扩展的情况下发出错误,并在/W4 处发出警告。但是,删除此代码将破坏以前编译的代码,Microsoft非常不愿意这样做。这也是他们不会修复他们的SFINAE支持的原因。

几年

和许多版本的Visual Studio之后,我们仍然有这个"扩展",引起惊喜和头痛。叹息。。。

解决方法是简单地将警告 C4239 变成错误。这将防止 MSVC 编译尝试将非常量左值引用绑定到临时引用的代码,并为您提供一个很好的清晰编译器错误。只需将/we4239添加到编译器定义或cl命令行参数即可。

在 Visual Studio 中:项目属性> C/C++> 所有选项>将特定警告视为错误>添加4239,并确保用分号分隔任何其他数字。

在CMake中:

if(MSVC)
    add_definitions("/we4239")
endif()

这似乎比使用 /Za 禁用所有语言扩展要好得多,官方不建议这样做。在我的大型代码库中,添加/Za会导致 Microsoft 自己的 winnt.h 标头出现 1500 多个编译器错误。

这个问题有一个更令人讨厌的变体:

class Foo {
  int _val;
public:
  Foo(int v) : _val(v) {}
  void F() { std::cout << _val << std::endl; }
};
class Bar {
  Foo& f;
public:
  Bar(Foo& f) : f(f) {}
  void F() { f.F(); }
};
int main() {
  Bar b(Foo(3));
  b.F();
}

那么:在打电话给b.F()时,b.f指向什么? 上面的示例使用 VS2013 默认调试设置编译,运行时不会崩溃并打印3,但我怀疑任何更复杂的示例都会导致堆栈损坏。 如果没有,并且编译器正在做一些"聪明"的事情来使其工作,那么我想它真正在做的是这样的:

class Foo {
  int _val;
public:
  Foo(int v) : _val(v) {}
  void F() { std::cout << _val << std::endl; }
};
class Bar {
  Foo f;
public:
  Bar(Foo&& f) : f(f) {}
  void F() { f.F(); }
};
int main() {
  Bar b(Foo(3));
  b.F();
}