2010-11-20 14 views
10

Recentemente mentre stavo spiegando a qualcuno la differenza di base tra riferimenti e puntatori (nel contesto della programmazione C++), ho detto le solite spiegazioni che parlano di argomenti di funzione differenti che passano le convenzioni - Call by valore, Call by pointer, Call by reference e tutta la teoria associata sui riferimenti.Riferimento C++ e puntatori const in C/C++

Ma poi ho pensato a qualsiasi cosa faccia un riferimento C + in termini di passaggio di argomenti, (Consente un modo efficiente di memoria di passare strutture/oggetti di grandi dimensioni, allo stesso tempo lo mantiene sicuro non permettendo al destinatario di modificare alcuna variabile dell'oggetto passato come riferimento, se il nostro design lo richiede)

Un puntatore const in C otterrebbe la stessa cosa, ad esempio Se bisogna passare un puntatore struttura dire struct mystr * ptr, colando il puntatore struttura come costante -

func(int,int,(const struct mystr*)(ptr)); 

sarà non PTR essere una sorta di equivalente a un riferimento?

  1. Will non funziona nel modo che sarebbe memoria efficiente non replicare la struttura (passaggio per puntatore), ma anche sicuro vietando qualsiasi modifica dei campi di struttura per il fatto che esso è passato come un puntatore const.

    Nel contesto di oggetto C++, si può passare puntatore const oggetto invece riferimento a un oggetto come ottenere stessa funzionalità)

  2. Se sì, allora lo scenario che cosa caso d'uso in C++, ha bisogno di riferimenti. Eventuali vantaggi specifici dei riferimenti e dei relativi inconvenienti?

grazie.

-AD

+3

@elusive: in che modo i puntatori sono meno "sicuri" rispetto ai riferimenti? – fredoverflow

risposta

3

ci sono due tipici scenari casi d'uso:

Prime: Indicatori denotano argomenti opzionali. Poiché, i riferimenti non possono essere NULL, ma i puntatori possono, documentare nello stile di codifica che qualsiasi argomento che è indicato come puntatore, può essere NULL, la funzione deve gestirlo. Gli argomenti facoltativi possono quindi essere const o non-const, come possono gli argomenti (di riferimento) obbligatori.

Secondo: i riferimenti vengono utilizzati solo in combinazione con la parola chiave const, poiché la sintassi di chiamata suggerisce la semantica del lettore pass-by-value, che è per definizione costante.Quindi i puntatori vengono utilizzati solo per argomenti che possono essere modificati dal destinatario.

Personalmente preferisco la prima opzione, perché ognuno dei quattro casi "riferimento const", "riferimento non const", "puntatore const", "puntatore non const" ha un significato diverso. L'opzione due distingue solo tra due "cose": "la funzione può modificare quel valore" contro "la funzione non modificherà quel valore".

+2

Non sono d'accordo sulle "funzioni che richiedono che i puntatori debbano sempre verificare null" - se qualcuno ti sta passando un puntatore nullo, di solito è il risultato di un grave errore di programmazione, e un crash è la cosa più ragionevole da fare. Se disponi di parametri veramente opzionali, è un segno che devi semplicemente avere una funzione diversa, sovraccaricata, oppure dovresti estrarre un oggetto metodo. –

+0

@Billy ONeal: In quel modello (che non è stato inventato al volo da me) lo scrittore di funzioni deve assicurarsi che denoti solo quegli argomenti come puntatori in cui dare 'NULL' in effetti non è un errore di programmazione grave. Esempio stupido: vuoi loggare, dare un logger non nullo alla funzione. Esempio meno stupido (ma libreria C): [sigprocmask] (http://www.kernel.org/doc/man-pages/online/pages/man2/sigprocmask.2.html). Dove è un errore dare 'NULL', la funzione dovrebbe prendere un riferimento in primo luogo. Sì, questo significa che la maggior parte delle funzioni prende solo riferimenti (o per valore, se è opportuno). – dennycrane

17

è possibile associare un riferimento const a un rvalue:

void foo(const std::string& s); 

foo(std::string("hello")); 

ma è impossibile passare l'indirizzo di un rvalue:

void bar(const std::string* s); 

bar(&std::string("hello")); // error: & operator requires lvalue 

I riferimenti sono stati introdotti in la lingua per supportare l'overloading dell'operatore. Vuoi essere in grado di dire a - b, non &a - &b. (Si noti che quest'ultimo ha già un significato:. Puntatore sottrazione)

Riferimenti principalmente supportano passaggio per riferimento, puntatori principalmente supportano semantica di riferimento. Sì, lo so, la distinzione non è sempre abbastanza chiara in C++.

+0

Ottieni il tuo punto, ma principalmente uno passerebbe un riferimento a un oggetto/variabile., Che sarebbe essenzialmente una variabile piuttosto che un const, quindi in quel caso ... – goldenmean

+6

@gold: Ah, stai parlando di non- riferimenti const. Sì, in quel caso, l'unica differenza pratica che vedo (oltre alla convenienza notazionale) è il fatto che non esiste un riferimento "nullo". Quindi se 'null' è un'opzione valida, usa un puntatore, altrimenti usa un riferimento. – fredoverflow

0

In termini di oggetto referente, quale codice può essere manipolato dato un riferimento const è lo stesso di quello che può fare con un puntatore a un oggetto const e, analogamente, ciò che può manipolare dato un riferimento non const è lo stesso dato un puntatore a un oggetto non const.

Quale riferimento impedisce alla funzione chiamata di eseguire è modificare a quale oggetto si riferisce il riferimento o l'aritmetica del puntatore sul riferimento.

In termini di chiamante, un riferimento const può essere associato direttamente a un valore rvalue e la semantica è ben definita durante la creazione e la distruzione di oggetti passati come argomenti. Questo è un linguaggio comune - costruire un temporaneo per argomento:

// declaration 
void bar (const Foo&); 

// use 
bar (Foo()); 

Ma non è immediatamente evidente che l'oggetto Foo in questi ha una durata che supera la lunghezza della chiamata di funzione:

// declaration 
void bar (const Foo*); 

// use 
Foo temp; 
bar (&temp); 

// cast to avoid warning about taking address of temporary 
bar (&static_cast<const Foo&>(Foo())); 

// helper function to same effect 
template<typename T> const T* address_of (const T& t) { return &t; } 

bar (address_of (Foo())); 

Sebbene ovviamente quest'ultimo, essendo solo una chiamata di funzione, dovrebbe renderlo evidente lo fa.

Fondamentalmente, i riferimenti sono zucchero sintattico per puntatori che puntano a singoli oggetti, non all'inizio di matrici.

+0

Penso che tu abbia confuso "const pointer" con "pointer to const". –

+0

@Ben riparato ora. –

+0

Ottimo! Ma la domanda potrebbe in realtà significare ciò che ha detto: "puntatore const" (come un riferimento, non può essere rimbalzo) piuttosto che "puntatore a const". –