2014-08-29 33 views
19

Capisco che se un temporaneo è associato a un membro di riferimento nell'elenco di inizializzazione del costruttore, l'oggetto verrà distrutto al ritorno del costruttore.Avviso spuria sull'associazione temporanea al membro di riferimento nel costruttore

Tuttavia, si consideri il seguente codice:

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

questo sembra perfettamente valido per me. L'oggetto callback vivrà durante l'intera esecuzione della funzione func e non dovrebbe essere eseguita alcuna copia temporanea per il costruttore wrapper.

Infatti, GCC 4.9.0 compila bene con tutti gli avvisi abilitati.

Tuttavia, GCC 4.8.2 compilatore mi dà il seguente avviso:

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

Si tratta di un falso positivo o sto equivoco le vite degli oggetti?

Qui sono le mie versioni esatte del compilatore testati:

$ 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

Disattivare le ottimizzazioni mi dà un difetto di seg. Valgrind sottolinea che il problema è da qualche parte intorno a 'func (std :: function const &) :: wrapper :: call()'. –

+2

L'uso di 'w_cb {cb}' comporta per me la violazione della segmentazione. L'uso di 'w_cb (cb)' non soffre dello stesso problema. Testato in g ++ 4.8.3. –

+0

Potrei riprodurre l'errore Valgrind con GCC 4.8.2. (Non un segfault, difficile, il programma emette 42 ed esce correttamente come previsto.) L'eseguibile prodotto da GCC 4.9.0 è Valgrind-clean. Queste osservazioni non cambiano con diversi livelli di ottimizzazione. – 5gon12eder

risposta

12

Si tratta di un bug di gcc 4.8 che è stato fissato a 4,9. Ecco la segnalazione di bug:

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

+1

Il fatto che il bug non sia * l'avvertimento *, ma piuttosto ciò di cui ti avvisa * l'avviso *, sarebbe utile. Dovevo andare al link per determinare che ... Cioè, un temporaneo è in realtà creato in gcc 4.8 e non dura abbastanza a lungo. Le ottimizzazioni possono far si che il temporaneo venga eliminato al di fuori dell'esistenza? – Yakk

+0

Sì, questo spiega cosa sta succedendo. Grazie per il link. Ho fatto qualche ulteriore ricerca ispirata da questo e lo posterò come risposta, ma accetterò il tuo. – 5gon12eder

+4

Si trattava di un bug nello standard e GCC stava implementando la formulazione precisa dello standard, che richiedeva un elemento temporaneo da creare lì. Il DR 1288 ha corretto lo standard. –

5

Come sottolineato da Howard Hinnant e già indicato dal commento di R Sahu, si tratta di un bug (che ha usato per essere richiesto dalla norma poi spezzato; grazie a Tony D per indicarlo) nel modo in cui GCC 4.8 tratta gli elenchi di inizializzatori.

Cambiare il costruttore nel mio esempio originale dal

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

a

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

rende l'avvertimento con GCC 4.8.3 andare via e il creato eseguibile Valgrind pulita. Il diff dei due file assembly è enorme, quindi non lo metto qui. GCC 4.9.0 crea codice di assemblaggio identico per entrambe le versioni.

Successivamente, ho sostituito lo std::function con una struct definita dall'utente e una copia eliminata e spostato i costruttori e gli operatori di assegnazione. In effetti, con GCC 4.8.3, questo mantiene l'avviso ma ora dà anche un errore (leggermente più utile) che la riga di codice sopra chiama il costruttore di copie cancellato della struct. Come previsto, non vi è alcuna differenza con GCC 4.9.0.

Problemi correlati