2014-08-29 12 views
19

Rozumiem, że jeśli tymczasowy jest powiązany z elementem referencyjnym na liście inicjalizacyjnej konstruktora, obiekt zostanie zniszczony podczas powrotu konstruktora.Niepożądane ostrzeżenie o powiązaniu tymczasowego z referencyjnym elementem w konstruktorze

Jednak, należy rozważyć następujący kod:

#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; 
} 

To wygląda doskonale ważny do mnie. Obiekt callback będzie działać podczas całego wykonywania funkcji func i nie należy wykonywać kopii tymczasowej dla konstruktora wrapper.

Rzeczywiście, GCC 4.9.0 kompiluje dobrze z włączonymi wszystkimi ostrzeżeniami.

Jednak GCC 4.8.2 kompilator daje mi następujące ostrzeżenie:

$ 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} { } 
              ^

Czy to fałszywy alarm czy mam nieporozumienie z wcieleń obiektu?

Oto moje dokładne przetestowane wersje kompilatora:

$ 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. 
+0

Wyłączenie optymalizacji daje mi błąd seg. Valgrind zwraca uwagę, że problem występuje gdzieś w pobliżu 'func (std :: function const &) :: wrapper :: call()'. –

+2

Użycie 'w_cb {cb}' powoduje naruszenie mojego segmentu. Używanie 'w_cb (cb)' nie cierpi z powodu tego samego problemu. Testowane w g ++ 4.8.3. –

+0

Mogłem odtworzyć błąd Valgrind z GCC 4.8.2. (Nie jest to usterka, trudna, program wyprowadza 42 i pomyślnie wychodzi zgodnie z oczekiwaniami.) Plik wykonywalny stworzony przez GCC 4.9.0 jest Valgrind-clean. Te obserwacje nie zmieniają się przy różnych poziomach optymalizacji. – 5gon12eder

Odpowiedz

12

Jest to błąd w gcc 4.8, który został ustalony w 4,9. Oto raport o błędzie:

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

+1

Fakt, że błąd nie jest ostrzeżeniem *, a raczej ostrzeżenie *, może być przydatny. Musiałem przejść do linku, aby ustalić, że ... Tj, tymczasowy jest rzeczywiście tworzony w gcc 4.8 i nie trwa wystarczająco długo. Optymalizacje mogą spowodować, że tymczasowy zostanie usunięty z istnienia? – Yakk

+0

Tak, to wyjaśnia, co się dzieje. Dzięki za link. Zrobiłem kilka dalszych badań zainspirowanych tym pomysłem i opublikuję je jako odpowiedź, ale przyjmuję twoje. – 5gon12eder

+4

To był błąd w standardzie, a GCC implementowało precyzyjne sformułowanie standardu, które _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ tymczasowy | DR 1288 naprawił standard. –

5

Jak podkreślił Howard Hinnant i już wskazano komentarzu R Sahu, jest to błąd (które były wymagane przez ówczesnego złamane normy; dzięki Tony D za wskazanie tego) w sposobie, w jaki GCC 4.8 traktuje listy inicjalizacyjne.

Zmiana konstruktora w moim oryginalnym przykład z

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

do

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

sprawia ostrzeżenie z GCC 4.8.3 odejść, a utworzony plik wykonywalny Valgrind czyste. Różnica dwóch plików zespołu jest ogromna, więc nie zamieszczam jej tutaj. GCC 4.9.0 tworzy identyczny kod zespołu dla obu wersji.

Następnie zastąpiłem std::function zdefiniowaną przez użytkownika strukturą i usuniętą kopią oraz przenoszę konstruktorów i operatorów przypisania. Rzeczywiście, w GCC 4.8.3, zachowuje to ostrzeżenie, ale teraz również daje (nieco bardziej pomocny) błąd, który powyższy wiersz kodu wywołuje konstruktor skasowanej kopii struktury. Zgodnie z oczekiwaniami, nie ma różnicy z GCC 4.9.0.

Powiązane problemy