2014-03-13 1 views
8

Vor kurzem sah ich eine Funktion, die als deklariert wird: ich weiß schonWas ist ein Verweis auf einen Zeiger?

void func(type* &param); 

den Unterschied zwischen type* param und type& param. Wie unterscheidet sich das obige von ihnen? Und wann sollte man das benutzen? Ist es ratsam, dies zu tun?

+9

Es ist genau wie 'type & param', und der Typ hier ist' type * '. – songyuanyao

Antwort

14

Die oben genannten können nicht nur das spitze Objekt, sondern auch den Zeiger in sich ändern. Als Beispiel den Code unten betrachten:

void func(int*& ptr) { 
    *ptr = 1; 
    ptr = 0; 
} 

int main() { 
    int x = 0; 
    int* y = &x; 
    func(y); 
} 

Am Ende der Ausführung, hat x Wert 1 und y ist 0 (wie Sie can see).

Beachten Sie, dass im Interesse des Beispiels I 0 als Null-Zeiger verwendet haben, aber wenn Sie C++ 11 Sie should probably use nullptr instead verwenden (was nicht eine überladene operaror<< für std::ostream hat).


Dieses Konzept möglicherweise durch einen Blick auf den folgenden Code assimiliert werden können:

template<class Type> using ptr = Type*; 
ptr<int>& x; 

oder

std::unique_ptr<int>& x; 

In diesen Beispielen x ist ein Verweis auf einen Typ (ptr<int> und dann std::unique_ptr<int>), was gerade ein Zeiger/Klasse mit Pointer Semantik (operator* und operator->).


Eine möglicherweise interessante digression kann auf der Position eines const Qualifier im Zeiger erfolgen. Betrachten Sie diese zwei Instanzen:

  1. void func(const int*& ptr)
  2. void func(int*const& ptr)

Ihre Bedeutungen sind:

  1. Zeiger durch Verweis auf einen konstanten int.
  2. Zeiger durch konstanten Verweis auf einen int.

Und im Anschluss an die oben Analogie mit ptr würden sie sein:

  1. ptr<const int>&
  2. ptr<int> const&

Deshalb ist die erste *ptr = 1 in den Körper der Funktion auszuführen fehl (weil Die int ist konstant), wird aber gerne ptr = 0 ausführen.

Die zweite verhält sich umgekehrt, erlaubt *ptr = 1 (weil der angegebene int ist nicht konstant), während ptr = 0 verbieten (weil der Zeiger konstant ist).

Natürlich im Fall von:

void func(const int*const& ptr) 

, die in der ptr Analogie ptr<const int> const& wären, würden sie beide nicht zugelassen werden.


Und wenn diese benutzen? Ist es ratsam, dies zu tun?

Wie jedes Feature finden Sie es nützlich, wenn Sie es brauchen. Aber als allgemeine Idee haben einige Leute den Zeiger nach dem Freigeben einer dynamisch zugewiesenen Ressource zurückgesetzt (ich empfehle das nicht, siehe unten).

Lassen Sie sich dieses Beispiel nehmen:

free_my_int(int*& ptr) { 
    delete ptr; 
    ptr = nullptr; 
} 

int* x = new int(42); 
free_my_int(x); 

Am Ende der Ausführung würde x richtig befreit und der Zeiger automatisch auf nullptr (Null-Zeiger). Dies wurde getan, um hässliche Segmentierungsfehler oder "Zeiger freigegeben wurde nicht zugeordnet" -Fehlermeldungen, die durch eine fehlende ptr = nullptr verursacht wurden, zu verhindern.

Aber mit C++ 11 und C++ 14 gibt es sehr wenig Verwendung von Zeigern und noch weniger von Verweis auf Zeiger. Die meisten Dingzeiger, für die sie verwendet werden, werden nicht durch andere Standardkonstrukte ersetzt (siehe beispielsweise std::optional, std::unique_ptr, std::shared_ptr oder std::reference_wrapper).

2

Lassen Sie uns alle drei Optionen vergleichen:

  • void func(type* param); // 'param' is a 'type*' variable
  • void func(type& param); // 'param' is a reference to a 'type' variable
  • void func(type*& param); // 'param' is a reference to a 'type*' variable

void func(type* param) 
{ 
    type x; 
    ... 
    param = &x; 
    // Argument 'param' is regarded as a local variable in this function, 
    // so setting 'param = ...' will have no effect outside this function 
} 

Natürlich, wenn Sie *param = ... tun, t Wenn es wird wird den Inhalt des Speichers, auf den param zeigt. Und Sie können auch param[5] = ... zum Beispiel tun und andere Bereiche innerhalb dieses Speicherplatzes beeinflussen.


void func(type& param) 
{ 
    type x; 
    ... 
    param = x; 
    // Argument 'param' is regarded as a reference to a variable outside this 
    // function, so setting 'param = ...' will effect the referenced variable 
} 

Hier finden Sie nur die referenzierte Variable ändern sich, so dass es sicherer ist als die Funktion als void func(type* param) erklärt, und übergeben Sie dann die Adresse von type param durch func(&param) aufrufen.


void func(type*& param) 
{ 
    type x; 
    ... 
    param = &x; 
    // Argument 'param' is regarded as a reference to a variable outside this 
    // function, so setting 'param = ...' will effect the referenced variable 
} 

Diese Funktion als void func(type** param) zu erklären, ähnlich ist, und dann die Adresse des type* param vorbei func(&param) Aufruf, aber auch hier ist es sicherer für den gleichen Grund wie oben erwähnt.