Предупреждение о временном объекте — это я или компилятор?

Следующий фрагмент дает предупреждение:

[C++ Warning] foo.cpp(70): W8030 Temporary used for parameter '_Val' in call to 'std::vector<Base *,std::allocator<Base *> >::push_back(Base * const &)'

.. на указанной строке.

class Base
{
};

class Derived: public Base
{
public:
 Derived()   // << warning disappears if constructor is removed!
 {
 };
};

std::vector<Base*> list1;
list1.push_back(new Base);
list1.push_back(new Derived);  // << Warning on this line!

Компилятор Codegear C++Builder 2007.

Как ни странно, если конструктор для Derived удаляется, предупреждение исчезает... Это я или компилятор?

РЕДАКТИРОВАТЬ: единственный способ, которым я нашел, чтобы удалить предупреждение, это что-то похожее на это:

Derived * d;
list1.push_back(d = new Derived);  // << No warning now...

person Roddy    schedule 25.05.2010    source источник
comment
Никаких предупреждений об этом коде с gcc.   -  person kriss    schedule 25.05.2010
comment
Вероятно, это не весь код. Имеют ли Base и Derived конструкторы (не сгенерированные компилятором)?   -  person Joris Timmermans    schedule 25.05.2010
comment
@MadKeithV - плюс-минус #include ‹vector›, это ВЕСЬ код. Я начал с гораздо более сложного случая и сократил его до голых костей, которые показывают проблему выше.   -  person Roddy    schedule 25.05.2010
comment
Ваша проблема связана с компилятором. У BCC32 много проблем, я думаю, это еще одна.   -  person daramarak    schedule 25.05.2010


Ответы (3)


Простая попытка:

list1.push_back(new Derived());

Я боюсь, что здесь есть что-то о POD (с тривиальными конструкторами) и не-POD.

ИЗМЕНИТЬ:

Учитывая, что код отлично компилируется с gcc.3.4.2 (--pedantic), я бы сказал, что это причуда компилятора. Я склоняюсь к MarkB объяснению, то есть компилятор создает временное, хотя я не понимаю, зачем это нужно, а затем жалуюсь при назначении его const&... но я все еще в недоумении.

person Matthieu M.    schedule 25.05.2010
comment
Раздражает, что у меня нет под рукой компилятора, чтобы поэкспериментировать с ним :/ Действительно странно, что такое же предупреждение не генерируется для Base: или, возможно, это потому, что Base не имеет определяемого пользователем конструктора? - person Matthieu M.; 25.05.2010
comment
В Base действительно был определяемый пользователем конструктор, но я убрал его, так как это не имело значения для проблемы. то есть использование «новой базы» никогда не давало предупреждения... - person Roddy; 25.05.2010
comment
Это похоже на ошибку компилятора. По этой проблеме есть открытый отчет QC, неверное предупреждение W8030. с почти идентичным фрагментом кода. qc.embarcadero.com/wc/qcmain.aspx?d=59272 - person Roddy; 26.05.2010

При вызове «передача по ссылке», если тип аргумента не соответствует «формальному параметру», компилятор попытается преобразовать аргумент в правильный тип. Аргумент будет рассматриваться как «параметр значения», если преобразование прошло успешно. В этом случае компилятор выдает предупреждение "Временно используется для...".

person Behnam Dezfouli    schedule 18.07.2016
comment
Работал на меня. int используется в беззнаковом параметре. - person Gilles Arcas; 05.05.2017

Поскольку list1 является вектором Base*, функция push_back в списке будет ожидать параметр типа Base* const&, в то время как ваша новая предоставляет Derived*. Для передачи по ссылке (как это необходимо в push_back) компилятору нужен фактический объект ссылочного типа, в данном случае Base*. Существует доступное неявное преобразование из Derived* в Base*, которое компилятор использует для создания временного объекта типа Base* для передачи в push_back, и компилятор предупреждает вас, что он создает этот временный объект.

Причина, по которой он работает, когда вы присваиваете его переменной, заключается в том, что больше не требуется неявное временное значение: он может неявно преобразовать именованную переменную в Base* неявно и передать эту ссылку.

Я думаю, вы можете отключить это предупреждение, сказав push_back рассматривать указатель как Base*:

list1.push_back(static_cast<Base*>(new Derived));

person Mark B    schedule 25.05.2010
comment
Хм. Актерский состав ничего не меняет, но я понимаю, о чем вы говорите. Однако я все еще не уверен в разнице между двумя неявными преобразованиями. - person Roddy; 25.05.2010
comment
Итак, почему наличие конструктора Derived() имеет значение...? - person Roddy; 25.05.2010
comment
Я думал об этом, но это не имеет для меня смысла. Если Derived* неявно преобразуется в Base* (как это имеет место), то почему Base* и Derived* должны обрабатываться по-разному? Я не вижу необходимости создавать временное от Derived* до Base* const& (кстати, проверьте позицию const в своем ответе), и const& в любом случае может быть ограничено временными... это меня беспокоит:/ - person Matthieu M.; 25.05.2010