Che cosa significa “int& foo()” significa in C++?

Durante la lettura questa spiegazione su lvalues e rvalues, queste righe di codice bloccato fuori a me:

int& foo();
foo() = 42; //OK, foo() is an lvalue

Ho provato a g++, ma il compilatore dice “undefined reference to foo()”. Se posso aggiungere

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

Compila bene, ma l’esecuzione dà un segmentation fault. Solo la linea

int& foo();

di per sé sia compila e si esegue senza problemi.

Che cosa fa questo codice significa? Come si può assegnare un valore a una chiamata di funzione, e perché non è un rvalue?

  • Non sei l’assegnazione di un valore ad una chiamata di funzione, si sta assegnando un valore di riferimento che ritorna.
  • assegnare un valore all’oggetto il riferimento è riferito a
  • il riferimento è l’oggetto, è un alias.
  • Sì, è un alias per l’oggetto; il riferimento non è l’oggetto
  • Ah. Questo riporta ricordi quando ho provato a programmare in c++ e non è riuscito. Questo ancora non è chiaro per me, anche dopo aver letto il 5 risposte. OTOH, ora ricordo perché Java è stato così caldo roba negli anni 90, anche se è stato più lento di lumache.
  • locale funzione dichiarazioni sono pox, personalmente sarei felice di vedere rimosso dalla lingua. (Escluse le espressioni lambda, naturalmente)
  • E ‘ strano che questo codice viene compilato con GCC versioni 4.7.4, 4.8.5, 4.9.3 e 5.3.0, ma non riesce a compilare con Clang 3.7.1 con error: functions that differ only in their return type cannot be overloaded. Probabilmente si dovrebbe aprire un bug report per GCC qui.
  • clang è giusto, ma quanto so compilatore non è obbligato a rilevare tutte le varianti di codice non valido.
  • Sì, ma penso che il GCC gente vorrei sapere se il loro compilatore compila codice pericoloso senza dare tutti avvertenze anche con -Wall -Wextra -Wshadow.
  • C’è già un GCC bug per questo.
  • Wow, questo è come 3 domande in un riferimento vs oggetto? undefined reference? locale dichiarazione di funzione?
  • Oh, giusto, sì, mi dispiace
  • La revisione di tutte le risposte ed i commenti postati, credo che solo @jotik indirizzi OP edizione viz., “Compila fine” <– che è quello che io considero OP del problema.

InformationsquelleAutor Sossisos | 2016-04-07

 

9 Replies
  1. 164

    La spiegazione è supponendo che vi sia un ragionevole attuazione per foo che restituisce un lvalue riferimento a un valido int.

    Ad una implementazione potrebbe essere:

    int a = 2; //global variable, lives until program termination
    
    int& foo() {
        return a;
    } 

    Ora, dal momento che foo restituisce un lvalue di riferimento, siamo in grado di assegnare qualcosa a che il valore di ritorno, in questo modo:

    foo() = 42;

    Questo aggiornamento globale a con il valore 42, che siamo in grado di controllare l’accesso alla variabile direttamente o chiamando foo di nuovo:

    int main() {
        foo() = 42;
        std::cout << a;     //prints 42
        std::cout << foo(); //also prints 42
    }
    • Ragionevole come operatore[] ? O qualche altro membro acces metodi?
    • Data la confusione circa refrences, probabilmente la scelta migliore per rimuovere le variabili locali statiche da campioni. L’inizializzazione aggiunge la complessità inutile, che è un ostacolo all’apprendimento. Appena globale.
  2. 71

    Tutte le altre risposte dichiarare statico all’interno della funzione. Penso che potrebbe confondere, in modo da prendere uno sguardo a questo:

    int& highest(int  & i, int  & j)
    {
        if (i > j)
        {
            return i;
        }
        return j;
    }
    
    int main()
    {
        int a{ 3};
        int b{ 4 };
        highest(a, b) = 11;
        return 0;
    }

    Perché highest() restituisce un riferimento, è possibile assegnare un valore ad esso. Quando questo viene eseguito, b sarà cambiato a 11. Se hai cambiato l’inizializzazione, in modo che a è stato, diciamo, 8, quindi a sarebbe cambiato a 11. Questa è una parte di codice che potrebbe servire a uno scopo, a differenza di altri esempi.

    • C’è un motivo per scrivere int{3} al posto di int a = 3? Questa sintassi non sembra adatto a me.
    • universale di inizializzazione. Mi è capitato di essere l’esempio che ho avuto a portata di mano. Niente di inappropriato su di esso
    • So di cosa si tratta. a = 3 si sente solo in modo molto più pulito. Preferenza personale)
    • Proprio come dichiara statico all’interno di una funzione può confondere alcune persone, credo anche l’utilizzo di universal inizializzazione è probabile.
  3. 31
    int& foo();

    Dichiara una funzione di nome pippo che restituisce un riferimento a un int. Cosa che gli esempi non riesce a fare è dare una definizione della funzione che si potrebbe compilare. Se usiamo

    int & foo()
    {
        static int bar = 0;
        return bar;
    }

    Ora abbiamo una funzione che restituisce un riferimento a bar. dal bar è static si continuerà a vivere dopo la chiamata alla funzione che restituisce un riferimento ad esso è sicuro. Ora, se noi

    foo() = 42;

    Quello che accade è che assegnare 42 a bar da quando abbiamo assegnare il riferimento e il riferimento è solo un alias per bar. Se chiamiamo la funzione di nuovo come

    std::cout << foo();

    Sarebbe di stampa 42 dal momento che abbiamo impostato bar a quella di cui sopra.

  4. 15

    int &foo(); dichiara una funzione chiamata foo() con tipo di ritorno int&. Se si chiama questa funzione senza fornire un corpo, allora è probabile che per ottenere un vago errore di riferimento.

    Nel secondo tentativo è fornito di una funzione int foo(). Questo è un diverso tipo di ritorno della funzione dichiarata da int& foo();. Così si hanno due dichiarazioni dello stesso foo che non corrispondono, che viola la Definizione di regole causando comportamenti indefiniti (non diagnostico richiesto).

    Per qualcosa che funziona, togliere i locali, dichiarazione di funzione. Si può portare a silent comportamenti indefiniti, come avete visto. Invece, utilizzare solo dichiarazioni di funzione al di fuori di ogni funzione. Il programma potrebbe apparire come:

    int &foo()
    {
        static int i = 2;
        return i;
    }  
    
    int main()
    {
        ++foo();  
        std::cout << foo() << '\n';
    }
  5. 10

    int& foo(); è una funzione che restituisce un riferimento a int. Il tuo forniti funzione restituisce int senza di riferimento.

    Si può fare

    int& foo()
    {
        static int i = 42;
        return i;
    }
    
    int main()
    {
        int& foo();
        foo() = 42;
    }
  6. 7

    int & foo(); significa che foo() restituisce un riferimento a una variabile.

    Considerare questo codice:

    #include <iostream>
    int k = 0;
    
    int &foo()
    {
        return k;
    }
    
    int main(int argc,char **argv)
    {
        k = 4;
        foo() = 5;
        std::cout << "k=" << k << "\n";
        return 0;
    }

    Questo codice stampa:

    $ ./un.fuori
    k=5

    Perché foo() restituisce un riferimento alla variabile globale k.

    Nel nuovo codice, si stanno gettando il valore restituito ad un riferimento, che è quindi non valido.

  7. 5

    In tale contesto, il & significa un punto di riferimento – così pippo restituisce un riferimento ad un int, piuttosto che un int.

    Non so se ti hanno lavorato con puntatori di sicurezza, ma è un idea simile, non siete realmente restituendo il valore della funzione – invece si sta passando le informazioni necessarie per trovare la posizione in memoria in cui che int è.

    Quindi, per riassumere non sei l’assegnazione di un valore ad una chiamata di funzione – si utilizza una funzione per ottenere un riferimento, e quindi di assegnare il valore a cui si fa riferimento a un nuovo valore. È facile pensare che tutto ciò che accade in una volta, ma in realtà il computer che fa tutto in un ordine preciso.

    Se vi state chiedendo il motivo per cui stai ricevendo un segmentation fault è perché stai tornando numerico, letterale, ‘2’, quindi è l’errore esatto che si otterrebbe se si dovesse definire un const int e quindi si tenta di modificare il suo valore.

    Se non hai imparato a conoscere i puntatori e memoria dinamica ancora quindi mi raccomando prima come ci sono alcuni concetti che penso che sono difficili da capire, a meno che si sta imparando tutti in una volta.

  8. 4

    Il codice di esempio alla pagina collegata è solo una finta dichiarazione di funzione. Non compilare, ma se si ha una certa funzione definita, si tratta in generale. L’esempio dire “Se hai avuto una funzione con questa firma, si potrebbe utilizzare come quello”.

    Nel tuo esempio, foo è chiaramente la restituzione di un lvalue in base alla firma, ma si torna un rvalue che viene convertito in un lvalue. Questo, chiaramente, è determinato a fallire. Si potrebbe fare:

    int& foo()
    {
        static int x;
        return x;
    }

    e vorresti riuscire a cambiare il valore di x, quando si dice:

    foo() = 10;
  9. 3

    La funzione foo(), è una funzione che restituisce un riferimento a un numero intero.

    Quindi diciamo che originariamente pippo restituito 5, e, più tardi, nella funzione principale, si dice foo() = 10;, quindi stampa pippo, verrà stampata 10 invece di 5.

    Spero che abbia un senso 🙂

    Sono nuovo di programmazione. È interessante vedere a domande come questa che ti fa pensare! 🙂

Lascia un commento