Предупреждение: не следует инициализировать неконстантную ссылку временным

Я получаю предупреждение из заголовка Sun Studio 12.1 со следующим фрагментом:

#include <vector>

std::vector<int> g()
{
  std::vector<int> result;
  result.push_back(5);
  return result;
}

int main()
{
  int b = g()[0];  // <- Warning in this line

  return b;
}

Текст предупреждения:

Warning: should not initialize a non-const reference with a temporary.

Хотя я знаю, что инициализация неконстантной ссылки временной — это плохо, я не понимаю, как это происходит здесь. Я знаю, что [0] возвращает ссылку на первый элемент вектора, который сам по себе является временным, но я не понимаю, в чем проблема.

Может кто-нибудь объяснить

  • Почему компилятор жалуется?
  • Is it a legitimate warning?
    • If yes, what do I have to change?
    • Если нет, как я могу элегантно заставить его замолчать?

person lytenyn    schedule 19.04.2011    source источник


Ответы (3)


Этот компилятор Sun выглядит очень странно, мне он вообще не кажется легитимным. У Ideone нет проблем с его компиляцией.

Что касается глушения:

std::vector<double> const tmp = g();
int b = tmp[0];

То есть ввести именованную переменную вместо того, чтобы оставить временную плавающую.

ИЗМЕНИТЬ:

Как было предложено в комментариях, может помочь константная квалификация возвращаемого значения.

std::vector<double> const g();

int main() {
  int b = g()[0];
  return b;
}
person Matthieu M.    schedule 19.04.2011
comment
да, это работает. Как-то неохота делать это везде. Возможно, я просто заглушу предупреждение в конце концов. - person lytenyn; 19.04.2011
comment
@lytenyn: вы можете попробовать изменить тип возврата g и добавить const. - person Matthieu M.; 19.04.2011
comment
@Matthieu: Это действительно сработало, спасибо! Есть ли недостатки? Я все еще могу сохранить возвращенный вектор в неконстантной переменной, если захочу. В чем разница между возвратом константного и неконстантного значения? - person lytenyn; 19.04.2011
comment
@lytenyn: единственный недостаток заключается в том, что компилятор, вероятно, предотвратит вызов неконстантных методов для возвращаемого объекта, здесь это сработало, потому что [] перегружен. Обычно самый верхний const следует игнорировать, но, учитывая ваш компилятор, я думаю, это имеет значение :) - person Matthieu M.; 19.04.2011
comment
@Matthieu: я читал кое-что о возвращаемых значениях const, предотвращающих семантику перемещения в C++0x, поэтому, вероятно, мне не следует добавлять сюда const? За исключением того, что Sun Studio еще не поддерживает C++0x;) - person lytenyn; 19.04.2011
comment
@lytenyn: действительно, я тоже думал о перемещении :) Сигнатура конструктора перемещения - Type(Type&& rhs), что эффективно предотвращает передачу объекта const (логично, поскольку вы собираетесь украсть его ресурсы и, таким образом, изменить его). Но я думал, что тебя это не коснется :) - person Matthieu M.; 19.04.2011

Нет, это не законно. Возвращаемое значение g() является временным, но неконстантным — вы просто не можете получить неконстантную ссылку на него. Здесь вполне допустим вызов неконстантного члена operator[], и преобразование double в integer столь же безопасно.

person Erik    schedule 19.04.2011
comment
согласовано. для справки: к g++ претензий нет - person sehe; 19.04.2011
comment
извините за преобразование double в int, это непреднамеренно и не относится к вопросу. Я отредактирую его соответственно. - person lytenyn; 19.04.2011
comment
g++, MSVC (без расширений), Comeau - ни один из них не жалуется. - person Erik; 19.04.2011
comment
Спасибо. Кто-нибудь знает, как избавиться от этого предупреждения, не отключая его глобально? - person lytenyn; 19.04.2011
comment
@lytenyn: Возможно, ищите прагмы для отключения предупреждений? Или используйте именованную промежуточную переменную. - person Erik; 19.04.2011
comment
@lytenyn: Кроме того, хакерский способ отключить предупреждение может заключаться в использовании .at() вместо [] - хотя семантика немного отличается - person Erik; 19.04.2011
comment
@Erik: да, в частности, это включает дополнительную проверку безопасности. - person lytenyn; 19.04.2011
comment
@lytenyn: Ага. Выберите свой яд, предупреждение или временную переменную или бессмысленную проверку границ :) - person Erik; 19.04.2011
comment
@Erik: почему переход на .at что-то меняет? Подпись в основном идентична, поэтому я не понимаю, как изменится интерпретация? - person Matthieu M.; 19.04.2011
comment
@Matthieu M: const в может не выдавать это предупреждение - просто догадки, трудно сказать, как несоответствующий компилятор действует в одной из ситуаций, когда он не соответствует стандарту. - person Erik; 19.04.2011

Да, он инициализирует неконстантную ссылку временной. Но только концептуально во время разрешения перегрузки, а не на самом деле. Компилятор не должен предупреждать об этом.

В разрешении перегрузки operator[] имеет эту сигнатуру функционального параметра

operator[](std::vector<int>&, std::vector<int>::size_type);

Первый параметр получит временное значение, возвращаемое g(), но, как сказано, это нормально, и C++ специально делает исключение для этой ссылки, которая является так называемым «неявным параметром объекта», так что разрешение перегрузки принимает временный аргумент.

person Johannes Schaub - litb    schedule 19.04.2011