2010-10-13 2 views
11

Stavo studiando i riferimenti dei puntatori e ho trovato diversi modi per alimentare i parametri. Qualcuno può spiegare cosa significa in realtà ciascuno?Quando è il momento giusto per usare *, & o const in C++?

Penso che il primo sia semplice, è che x è una copia del parametro immesso in modo che venga creata un'altra variabile nello stack. Per quanto riguarda gli altri, sono incompetente.

void doSomething1(int x){ 
    //code 
} 
void doSomething2(int *x){ 
    //code 
} 

void doSomething3(int &x){ 
    //code 
} 
void doSomething3(int const &x){ 
    //code 
} 

Vedo anche cose come questo quando vengono dichiarate le variabili. Non capisco le differenze tra loro. So che il primo inserirà 100 nella variabile nello stack. Non creerà un nuovo indirizzo o altro.

//example 1 
int y = 100; 

//example 2 
int *y = 100; 

//Example 3: epic confusion! 
int *y = &z; 

Domanda 1: come utilizzare questi metodi? Quando è più appropriato?

Domanda 2: Quando si dichiarano le variabili in questo modo?

Gli esempi sarebbero grandiosi.

P.S. questo è uno dei motivi principali per cui non ho imparato il C++ in quanto Java ha solo la garbage collection. Ma ora devo entrare in C++.

+2

Vedere [questa risposta] (http://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c/2139254#2139254) per alcune regole empiriche su come passare i parametri alle funzioni in C++. – sbi

+0

Buona discussione qui: http: // StackOverflow.it/questions/2550377/when-pass-by-pointer-is-preferred-to-pass-by-reference-in-c/2550405 # 2550405 –

risposta

2

Leggere il C++ Premier di S.Lippmann o qualsiasi altro buon libro C++. Per quanto riguarda il passaggio dei parametri, generalmente quando la copia è a buon mercato passiamo di valore. Per i parametri out obbligatori utilizziamo i riferimenti, per i parametri opzionali out - puntatori, per i parametri di input in cui la copia è costosa, passiamo con riferimenti const

0

Il momento migliore per utilizzare questi metodi è quando è più efficiente passare i riferimenti rispetto ai riferimenti a interi oggetti. A volte, alcune operazioni sulla struttura dei dati sono anche più veloci usando i riferimenti (inserendo in un elenco collegato, per esempio). Il modo migliore per capire i puntatori è leggerli e poi scrivere programmi per usarli (e confrontarli con le loro controparti pass-by-value).

E per la cronaca, la conoscenza dei puntatori ti rende molto più prezioso sul posto di lavoro. (troppo spesso, i programmatori C++ sono i "mistici" dell'ufficio, con la conoscenza di come quelle scatole magiche sotto i banchi elaborano codice/semi-sarcasmo)

+0

non parlare di "leggere un libro". Lo sottovalutano: D: D: D –

+0

Bene, allora così sia - è la verità a prescindere. – SubSevn

+1

Lo è sicuramente. Insisto sul fatto che il C++ sia studiato sistematicamente. C++ è molto utile per "provare" qualcosa e "Wow it woked => è corretto" –

4

Da Scott Myers - più efficace C++ -> 1

In primo luogo, riconoscere che non esiste una cosa come un riferimento null. Un riferimento deve sempre fare riferimento ad alcuni oggetti. Poiché un riferimento deve riferirsi ad un oggetto, C++ richiede che i riferimenti siano inizializzati.

I puntatori non sono soggetti a tali restrizioni. Il fatto che non esista un riferimento null implica che può essere più efficiente utilizzare i riferimenti piuttosto che utilizzare i puntatori. Questo perché non è necessario testare la validità di un riferimento prima di utilizzarlo.

Un'altra importante differenza tra puntatori e riferimenti è che i puntatori possono essere riassegnati per fare riferimento a oggetti diversi.Un riferimento, tuttavia, fa sempre riferimento all'oggetto con cui è inizializzato

In generale, è necessario utilizzare un puntatore ogni volta che è necessario prendere in considerazione la possibilità che non vi sia nulla a cui fare riferimento (in tal caso è possibile impostare il puntatore a null) o ogni volta che è necessario essere in grado di riferirsi a cose diverse in tempi diversi (nel qual caso è possibile modificare la posizione del puntatore). Dovresti usare un riferimento ogni volta che sai che ci sarà sempre un oggetto a cui fare riferimento e sai anche che una volta che ti stai riferendo a quell'oggetto, non vorrai mai fare riferimento a nient'altro.

I riferimenti, quindi, sono la caratteristica di scelta quando si sa che si ha qualcosa a cui fare riferimento, quando non si vorrà più fare riferimento a qualcos'altro e quando si implementano operatori i cui requisiti sintattici rendono indesiderabile l'utilizzo di puntatori. In tutti gli altri casi, attenersi ai puntatori.

1

vuoto doSomething1 (int x) {// codice } Questa passare la variabile per valore, comunque vada all'interno della funzione, la variabile originale non cambia

vuoto doSomething2 (int * x) { // codice } Qui si passa una variabile di tipo puntatore a numero intero. Così, quando si accede al numero che si dovrebbe usare * x per il valore o x per l'indirizzo

vuoto doSomething3 (int & x) {// codice } Ecco come il primo, ma qualunque cosa accada all'interno della funzione , verrà modificata anche la variabile originale

int y = 100; numero intero normale

// esempio 2 int * y = 100; puntatore all'indirizzo 100

// Esempio 3: confusione epica! int * y = & z; puntatore all'indirizzo di z

1
void doSomething1(int x){ 
//code 
} 
void doSomething2(int *x){ 
//code 
} 

void doSomething3(int &x){ 
//code 
} 

e sono davvero fare confusione tra di loro?

Il primo utilizza il pass-by-value e l'argomento della funzione manterrà il suo valore originale dopo la chiamata.

Gli ultimi due utilizzano il riferimento pass-by. Essenzialmente sono due modi per ottenere la stessa cosa. L'argomento non è garantito per mantenere il suo valore originale dopo la chiamata.

La maggior parte dei programmatori preferisce passare oggetti di grandi dimensioni con riferimento const per migliorare le prestazioni del proprio codice e fornire un vincolo per il fatto che il valore non cambierà. Ciò garantisce che il costruttore di copie non venga chiamato.

La confusione potrebbe essere dovuta all'operatore "&" con due significati. Quello che ti sembra familiare è l''operatore di riferimento'. Viene anche utilizzato come "operatore di indirizzi". Nell'esempio che hai dato prendi l'indirizzo di z.

Un buon libro da controllare che copre tutto questo in dettaglio è 'Accelerated C++' di Andrew Koening.

10
//example 1 
int y = 100; 

//example 2 
int *y = 100; 

//Example 3: epic confusion! 
int *y = &z; 

Credo che il problema per la maggior parte degli studenti è che in C++ sia & e * hanno significati diversi, a seconda del contesto in cui vengono utilizzati.
Se una di esse appare dopo un tipo all'interno di una dichiarazione oggetto (T* o T&), sono modificatori di tipo e cambiare il tipo da pianura T a un riferimento a un T (T&) o un puntatore a T (T*).
Se sembrano davanti un oggetto (&obj o *obj), sono operatori prefissi unari invocati sull'oggetto. Il prefisso & restituisce l'indirizzo dell'oggetto viene invocato per , *dereferenziazioni un puntatore, ecc iteratore, cedendo il valore fa riferimento.

Non aiuta la confusione che i modificatori di tipo si applicano all'oggetto che viene dichiarato, non al tipo. Cioè, T* a, b; definisce un T* nome a e una pianura T chiamato b, motivo per cui molte persone preferiscono scrivere T *a, b; invece (si noti il ​​posizionamento del tipo modificanti * adiacente l'oggetto in fase di definizione, invece che il tipo modificato).

Anche inutile è che il termine "riferimento" è sovraccarico. Per prima cosa significa un costrutto sintattico, come in T&. Ma c'è anche il significato più ampio di un "riferimento" che è qualcosa che si riferisce a qualcos'altro. In questo senso, sia un puntatore T* sia un riferimento (altro significato T&) sono riferimenti, in quanto fanno riferimento ad un oggetto. Questo entra in gioco quando qualcuno dice che "un puntatore fa riferimento ad un oggetto" o che un puntatore è "dereferenziato".

Quindi nel tuo casi specifici, # 1 definisce una pianura int, # 2 definisce un puntatore ad un int e l'inizializza con l'indirizzo 100 (qualunque cosa ci vive è probabilmente meglio lasciare intatta), e # 3 definisce un altro puntatore e lo inizializza con l'indirizzo di un oggetto z (necessariamente anche int).


A per come passare gli oggetti per le funzioni in C++, here è un vecchio risposta da me per questo.

+0

quindi fa una grande differenza quando scrivi * dopo T o prima *. woah. – Pavan

+0

@Pavan: non è possibile utilizzare in modo intercambiabile, poiché, a seconda che 'T' sia il nome di un tipo o di un oggetto, solo uno di essi è valido. – sbi

+0

La domanda ora è se 'T & t;' si trova di fronte a un oggetto o dopo un tipo :) –