2014-06-19 11 views
7

Cosa cercano di comunicare le domande frequenti su C++ this?Prendere l'indirizzo di un membro statico Domande frequenti sul C++

You can take the address of a static member if (and only if) it has an out-of-class definition :

class AE { 
    // ... 
public: 
    static const int c6 = 7; 
    static const int c7 = 31; 
}; 

const int AE::c7; // definition 

int f() 
{ 
    const int* p1 = &AE::c6; // error: c6 not an lvalue 
    const int* p2 = &AE::c7; // ok 
    // ... 
} 

Tuttavia questo compiles !

+1

Cosa succede se si compila 'classe AE' e' f() 'separatamente e quindi si collegano gli oggetti? – juanchopanza

+1

@juanchopanza Si compila con '-O2' e' f() 'è essenzialmente un nop. Tuttavia, fornisce un errore del linker con '-O0', come il programma originale con' -O0'. – Csq

+0

@Csq Sì, ho visto e ho votato la tua risposta. In alternativa, 'std :: cout << p1 << std :: endl;' farebbe in un op. – juanchopanza

risposta

5

Il commento nelle FAQ è molto fuorviante; sia AE::c6 e AE::c7 sono lvalue. Se non esiste una definizione di AE::c7, il codice in questione viola la regola una sola definizione:

An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied. [...]

[...]

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

In pratica, il linker generalmente genererà un errore se il compilatore in realtà necessario l'indirizzo dell'oggetto. Nel tuo caso , se il p2 non viene utilizzato in seguito, il compilatore non avrà bisogno dell'indirizzo , poiché l'ottimizzazione rimuoverà la definizione di p1. Un caso ancora più frequente in cui questo avviene sono cose come il seguenti:

std::vector<int> v; 
v.push_back(AE::c6); 

Da std::vector<>::push_back prende un riferimento, non c'è immediata conversione Ivalue a rvalue e una definizione è richiesto. In pratica, std::vector<>::push_back è una funzione modello (di solito in linea), quindi il compilatore può vedere nella sua implementazione e propagare il valore nella funzione nel punto in cui si verifica la conversione da lvalue a valore effettivo in realtà e il codice verrà compilato e funzionerà. Ma è ancora comportamento formalmente indefinito.

9

si utilizza -O2 per la compilazione. Il compilatore può ottimizzare l'assegnazione di const int* p1 = &AE::c6; (poiché non ha alcun effetto) e quindi non ha bisogno dell'indirizzo di AE::c6 nel codice finale, ecco perché compila.

Fornisce un errore del linker senza ottimizzazione.

È inoltre incluso un errore di linker se si inizia ad utilizzare p1 (ad esempio std::cout << p1 << p2 << std::endl;) Link

+0

Ok, dirò la stessa cosa anche qui (come ho detto in una delle risposte cancellate), il commento '// errore: c6 non è un lvalue' nelle FAQ IMO è fuorviante, che sembra essere un errore sintattico a prima vista. L'errore del linker era ovvio, ma a me sorprendentemente sconosciuto dopo l'ottimizzazione – P0W

Problemi correlati