Valore del passaggio per riferimento [duplicato]

0

In C ++, abbiamo la possibilità di passare per riferimento o passare per valore.

Il codice cliente non ha bisogno di sapere quale usa una funzione genitore; cioè, int func(int param) e int func(int &param) sono chiamati esattamente nello stesso modo dal codice cliente. Non è pericoloso?

Se scrivo codice sul lato client, non so quale delle variabili che passo a una funzione possa essere cambiata e quale posso aspettarmi di rimanere la stessa senza una conoscenza esplicita della dichiarazione della funzione genitore. Qual è il vantaggio di farlo in questo modo rispetto a un esplicito puntatore (ad esempio int func(int *param) , che verrebbe chiamato func(&param); )?

Quando devi avere un puntatore, è abbastanza facile che il cliente sappia quali valori possono essere modificati, quelli che hanno un & in primo piano. In alternativa, perché non fare in modo che ogni cosa sia pass-by-reference, in modo che non ci siano congetture di "Può questa funzione cambiare questo valore?" La risposta è universalmente sì.

    
posta wolfPack88 09.07.2014 - 14:40
fonte

2 risposte

1

If I'm writing code on the client side, I don't know which of the variables I pass to a function might be changed and which I can expect to remain the same without an explicit knowledge of the parent function declaration.

Questo è come dovrebbe essere. Quando chiami un'API, dovresti sapere cosa stai chiamando e perché. Dovresti anche sapere cosa fa la funzione e quali sono gli effetti collaterali (e anche le precondizioni e le postcondizioni).

What is the advantage of doing it this way versus explicitly expecting a pointer (e.g., int func(int *param), which would then be called func(&param);)?

Suppongo che "farlo in questo modo" significhi "passare per riferimento".

Mi sembra che tu abbia reso l'associazione "ricevuta da pointer = may be changed". Questo non è corretto.

Ecco due scenari in cui il passaggio per riferimento / puntatore è preferibile rispetto all'alternativa:

  • operatori:

    class EvenInteger { int value; public: /*...*/ }; // 0, 2, 4, 6, ...
    
    EvenInteger operator +(const EvenInteger& x, const EvenInteger&y);
    

    Qui, passando per riferimento si disattiva l'operatore per i valori temporanei, passando per puntatore si otterrebbe un codice client come questo:

    EvenInteger a{0}, b{122};
    auto c = &a + &b; // addition by address imposed if operator received pointers
    
  • istanza dell'osservatore (naturalmente passare 'this' come argomento):

    class Collection // collection/sequence of arbitrary objects of type Obj
    {
    public:
        class InterestingIterator {
            Collection* parent;
            InterestingIterator(Collection* c); // accessible by Collection
        public:
            // ...
        }
    
        InterestingIterator begin() { return InterestingIterator{this}; }
    };
    

    L'implementazione di begin , riceve naturalmente un puntatore this , senza implicare che sia in alcun modo un valore di ritorno. Scrivere l'iteratore per ricevere un riferimento impone il costrutto *this sul codice client.

Di norma, l'interfaccia di un'API dovrebbe dirti questo:

void f(int x); // makes own copy of x, doesn't return/alter value
void f(int& x); // _may_ alter value (check docs)
void f(int* x); // _may_ alter value, or populate it with a return (check docs)
void f(const int& x); // observer of x
void f(int* const x); // _may_ alter value pointed by x, but not the address
void f(const int* x); // _may_ alter address, but not the pointed value
void f(const int* const x); // observer of value and address

Come puoi vedere, dovresti (sempre) fare affidamento sulla documentazione dell'API. Se ti affidi a una firma di funzione, può solo dirti quando non altera i suoi parametri ricevuti, e lo vedi attraverso const , non attraverso il tipo di parametro (indirizzo / riferimento / etc ).

Ciò implica anche che devi sempre scrivere la documentazione per le tue API.

    
risposta data 09.07.2014 - 16:36
fonte
0

Le differenze tra riferimenti e puntatori sono state ampiamente discusse, a volte anche qui. Questa discussione probabilmente non dovrebbe essere Cominciato.

Ma l'altra domanda: "Perché non avere tutto come X o Y?" è facilmente risposta. C ++ ti offre entrambe le opzioni in linea di principio, perché potresti voler usare X, ma potresti anche voler usare Y.

In questi casi il linguaggio offre praticamente sempre entrambi sul principio che se una delle due consente una soluzione leggermente migliore, più efficace ecc., allora la lingua deve contenere entrambe. Ricorda che puoi perfino scrivere i tuoi allocatori di memoria e deallocatori specifici per classe. I progettisti di linguaggi sono fermamente convinti che almeno alcuni dei loro utenti saranno in grado di costruire un allocatore speciale migliore di quello che potrebbero costruire nel compilatore, quindi non devono fare nulla che lo impedisca. Questo è parte del motivo per cui C ++ ha un insieme straordinariamente ricco di funzioni interattive, anche quando sono solo leggermente diverse.

    
risposta data 09.07.2014 - 14:49
fonte

Leggi altre domande sui tag