一个VS2010的bug?允许将非const引用绑定到rvalue而不发出警告?

时间:2011-08-25 11:16:21

标签: c++ visual-studio-2010 reference lvalue rvalue

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&
  2. 的临时类型初始化std::string类型的非const引用无效
  3. VS2008并不算太差,因为至少它提供了编译警告: 警告C4239:使用非标准扩展名:'初始化': 从std::string转换为std::string &非const 引用只能绑定到左值
  4. 这是一个有问题的 - VS2010(SP1)没有任何优点 错误或警告,为什么?? !! 我知道VS2010中的右值引用可用于绑定rvalue,但我没有使用&&,而是在演示代码中,我只是使用非const左值引用!
  5. 能否帮助我解释一下VS2010的行为?这是一个错误!? 感谢

4 个答案:

答案 0 :(得分:11)

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

答案 1 :(得分:9)

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

答案 2 :(得分:0)

Visual Studio的很多年和很多版本以后,我们仍然有这种“扩展”,这会引起意外和头痛。 igh ...

解决方法是将警告C4239变成错误。这将防止MSVC编译试图将非const左值引用绑定到临时代码的代码,并给您带来清晰的编译器错误。只需将/we4239添加到编译器定义或cl命令行参数中即可。

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

在CMake中:

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

这似乎比使用/Za的{​​{3}}更好,后者正式不建议这样做。在我的大型代码库中,添加/Za会导致Microsoft自己的winnt.h标头产生1500多个编译器错误。

答案 3 :(得分:-1)

这个问题有一个更糟糕的变种:

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默认的Debug设置编译,运行时不会崩溃并打印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();
}