Ложное предупреждение о привязке временного элемента к элементу ссылки в конструкторе


Я понимаю, что если временный элемент привязан к ссылочному члену в списке инициализаторов конструктора, объект будет уничтожен по мере возврата конструктора.

Однако , рассмотрим следующий код:

#include <functional>
#include <iostream>

using callback_func = std::function<int(void)>;

int
func(const callback_func& callback)
{
  struct wrapper
  {
    const callback_func& w_cb;
    wrapper(const callback_func& cb) : w_cb {cb} { }
    int call() { return this->w_cb() + this->w_cb(); }
  };
  wrapper wrp {callback};
  return wrp.call();
}

int
main()
{
  std::cout << func([](){ return 21; }) << std::endl;
  return 0;
}

Мне это кажется вполне обоснованным. Объект callback будет жить в течение всего выполнения функции func, и никакая временная копия не должна быть сделана для конструктора wrapper.

Действительно, GCC 4.9.0 прекрасно компилируется со всеми предупреждениями включен.

Однако, GCC 4.8.2 компилятор выдает мне следующее предупреждение:

$ g++ -std=c++11 -W main.cpp 
main.cpp: In constructor ‘func(const callback_func&)::wrapper::wrapper(const callback_func&)’:
main.cpp:12:48: warning: a temporary bound to ‘func(const callback_func&)::wrapper::w_cb’ only persists until the constructor exits [-Wextra]
     wrapper(const callback_func& cb) : w_cb {cb} { }
                                            ^

Является ли это ложным позитивом или я неверно истолковываю время существования объекта?

Вот мои точные версии компилятора, проверенные:

$ g++ --version
g++ (GCC) 4.8.2
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ --version
g++ (GCC) 4.9.0 20140604 (prerelease)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
2 19

2 ответа:

Это ошибка в gcc 4.8, которая была исправлена в 4.9. Вот отчет об ошибке:

Https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50025

Как указал Говард Хиннант и уже указал комментарий R Sahu, это ошибка (которая требовалась в то время нарушенным стандартом; спасибо Тони D за указание на это) в том, как GCC 4.8 обрабатывает списки инициализаторов.

Изменение конструктора в моем исходном примере из

wrapper(const callback_func& cb) : w_cb {cb} { }

К

wrapper(const callback_func& cb) : w_cb (cb) { }

Удаляет предупреждение с GCC 4.8.3 и очищает созданный исполняемый файл Valgrind. Разница между двумя файлами сборки огромна, поэтому я не публикую ее здесь. GCC 4.9.0 создает идентичный ассемблерный код для обеих версий.

Затем я заменил std::function пользовательской структурой и удалил конструкторы копирования и перемещения и операторы присваивания. Действительно, с GCC 4.8.3 это сохраняет предупреждение, но теперь также дает (немного более полезную) ошибку, что вышеупомянутая строка кода вызывает конструктор удаленной копии структуры. Как и ожидалось, нет никакой разницы с GCC 4.9.0.