Ответ 1
Это ошибка в gcc 4.8, которая исправлена в 4.9. Вот отчет об ошибке:
Я понимаю, что если временное привязано к ссылочному элементу в списке инициализатора конструктора, объект будет уничтожен при возврате конструктора.
Однако, рассмотрите следующий код:
#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.
Это ошибка в gcc 4.8, которая исправлена в 4.9. Вот отчет об ошибке:
Как указал Говард Хиннант и уже обозначенный комментарием R Sahu, это ошибка (которая раньше требовалась тогдашним нарушением стандарта, благодаря Tony 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.