Один баг VS2010?Разрешить обязательную неконстантную ссылку на rvalue БЕЗ ДАЖЕ предупреждение? - PullRequest
9 голосов
/ 25 августа 2011
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
  2. VS2008 не так уж и плох, поскольку, по крайней мере, выдает предупреждение о компиляции : предупреждение C4239: используется нестандартное расширение: 'initializing': преобразование из std::string в std::string & Неконстантная ссылка может быть толькопривязанный к lvalue
  3. Вот и проблемный - VS2010 (SP1) прекрасно работает БЕЗ любой ошибки или предупреждения, ПОЧЕМУ ?? !!Я знаю, что ссылку на rvalue в VS2010 можно использовать для привязки с rvalue, но я НЕ использую &&, вместо этого в демонстрационном коде я просто использовал неконстантную ссылку на lvalue!

Может ли кто-нибудь помочь мне объяснить поведение VS2010 здесь?Это ошибка!?Спасибо

Ответы [ 4 ]

12 голосов
/ 25 августа 2011

Это известная проблема / особенность компиляторов VS. Они всегда это допускали, и, похоже, нет никакого толчка в удалении этого расширения .

9 голосов
/ 25 августа 2011

Компилятор выдаст ошибку с включенным отключением языковых расширений и предупреждением в / W4. Однако удаление этого кода нарушит ранее скомпилированный код, и Microsoft очень неохотно делает это. Именно поэтому они не исправят свою поддержку SFINAE.

0 голосов
/ 11 июля 2019

Несколько лет спустя и многие версии Visual Studio у нас все еще есть это «расширение», вызывающее сюрпризы и головные боли. Вздох ...

Исправление состоит в том, чтобы просто превратить предупреждение C4239 в ошибку. Это предотвратит компиляцию кода MSVC, который пытается привязать неконстантную ссылку lvalue к временному, и даст вам хорошую ясную ошибку компилятора. Просто добавьте /we4239 в определения вашего компилятора или cl аргументы командной строки.

В Visual Studio: Свойства проекта> C / C ++> Все параметры> Рассматривать определенные предупреждения как ошибки> добавьте 4239 и убедитесь, что все остальные числа разделены точкой с запятой.

В CMake:

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

Кажется, это работает намного лучше, чем отключение всех языковых расширений с помощью /Za, что официально не рекомендуется. На моей большой базе кода добавление /Za вызвало более 1500 ошибок компиляции из собственного заголовка winnt.h в Microsoft.

0 голосов
/ 11 августа 2014

Существует гораздо более неприятный вариант этой проблемы:

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();
}
...