it-swarm.com.de

Funktion in C++ gibt nach Wert oder Referenz zurück?

Wenn eine Funktion (Angerufene) eine Menge an die aufrufende Funktion zurückgibt, wird sie als Wert oder als Referenz zurückgegeben?

Die Sache ist, dass ich eine Funktion geschrieben habe, die einen sehr großen Vektor erzeugt, wenn sie aufgerufen wird. Ich möchte diesen großen Vektor an die aufrufende Funktion zurückgeben (in diesem Fall main()), indem ich mich ständig darauf beziehe, damit ich sie weiter verarbeiten kann.

Ich hatte Zweifel, weil mir gesagt wurde, dass, wenn eine C++ - Funktion zurückgegeben und beendet wird, alle dieser Funktion zugeordneten Variablen/Speicher gelöscht werden.

struct node{

string key;
int pnum;
node* ptr;
}

vector< vector<node> > myfun1(/*Some arguments*/)
{

/*Build the vector of vectors. Call it V*/

return v;

}

int main(void)
{
a=myfun1(/* Some arguments */)
}
16
smilingbuddha

C++ - Funktionen können nach Wert, nach Referenz (aber keine lokale Variable nach Referenz zurückgeben) oder nach Zeiger (auch hier kein lokaler nach Zeiger zurückgeben).

Bei der Rückgabe nach Wert kann der Compiler häufig Optimierungen vornehmen, die die Rückgabe nach Referenz ebenso schnell wie die Rückgabe nach Referenz machen, ohne das Problem, dass Referenzen hängenbleiben. Diese Optimierungen werden allgemein als "Rückgabewertoptimierung (RVO)" und/oder "Named Return Value Optimization (NRVO)" bezeichnet.

Eine andere Möglichkeit für den Aufrufer, einen leeren Vektor (als Referenz) bereitzustellen und ihn durch die Funktion ausfüllen zu lassen. Dann muss er nichts zurückgeben.

Sie sollten auf jeden Fall diesen Blog-Beitrag lesen: Willst du Geschwindigkeit? Übergebe den Wert.

25
Ben Voigt

Standardmäßig wird alles in C/C++ als Wert übergeben, einschließlich des Rückgabetyps, wie im folgenden Beispiel gezeigt:

T foo() ;

In C++, wo die Typen normalerweise als Werttypen betrachtet werden (d. H. Sie verhalten sich wie int- oder double-Typen), kann die zusätzliche Kopie kostspielig sein, wenn die Konstruktion/Zerstörung des Objekts nicht trivial ist.

Mit C++ 03

Wenn Sie als Referenz oder als Zeiger zurückgeben möchten, müssen Sie den Rückgabetyp in einen der folgenden Werte ändern:

T & foo() ;  // return a reference
T * foo() ;  // return a pointer

aber in beiden Fällen sie müssen sicherstellen, dass das zurückgegebene Objekt nach der Rückgabe noch vorhanden ist. Wenn das zurückgegebene Objekt beispielsweise im Hauptteil der Funktion dem Stapel zugewiesen wurde, wird das Objekt zerstört, und daher ist sein Verweis/Zeiger ungültig.

Wenn Sie nicht garantieren können, dass das Objekt nach der Rücksendung noch vorhanden ist, können Sie nur Folgendes tun:

  1. akzeptieren Sie die Kosten für eine zusätzliche Kopie und hoffen Sie auf eine Rückgabewertoptimierung
  2. Übergeben Sie stattdessen eine Variable als Referenz als Parameter an die Funktion, wie im Folgenden beschrieben:

void foo(T & t) ;

Auf diese Weise setzen Sie innerhalb der Funktion den Wert t nach Bedarf, und nach der Rückkehr der Funktion erhalten Sie Ihr Ergebnis.

Mit C++ 11

Wenn Sie nun die Möglichkeit haben, mit C++ 0x/C++ 11 zu arbeiten, dh mit einem Compiler, der r-Wertereferenzen/Verschiebungssemantik unterstützt, wenn Ihr Objekt den richtigen Konstruktor/Operator hat ( Wenn Ihr Objekt aus der Standardbibliothek stammt, ist es in Ordnung, dann wird die zusätzliche temporäre Kopie entfernt und Sie können die Notation behalten:

T foo() ;

Zu wissen, dass der Compiler keinen unnötigen temporären Wert generiert.

21
paercebal

Es wird von dem zurückgegeben, was Sie als Rückgabetyp deklarieren. vector<int> f(); und vector<int>& f(); geben nach Wert bzw. Referenz zurück. Es wäre jedoch ein schwerwiegender Fehler, einen Verweis auf eine lokale Variable in der Funktion zurückzugeben, da dieser beim Beenden des Funktionsumfangs weggeblasen wurde.

Gute Tipps zum effizienten Zurückgeben großer Vektoren aus einer Funktion finden Sie unter diese Frage (in der Tat handelt es sich hier vermutlich um ein Duplikat davon).

3
timday

Die Funktion gibt das zurück, was Sie ihr mitteilen. Wenn Sie eine vector zurückgeben möchten, wird diese vom Aufrufer in die Variable hold kopiert. Sofern Sie dieses Ergebnis nicht mit const reference erfassen, müssen Sie es in diesem Fall nicht kopieren. Es gibt Optimierungen, mit denen Funktionen dieses zusätzliche Kopierkonstrukt vermeiden können, indem sie das Ergebnis in dem Objekt platzieren, das den Rückgabewert enthält. Sie sollten dies lesen, bevor Sie Ihr Design für die Leistung ändern:

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

2
K-ballo

C++ kann entweder als Referenz oder als Wert zurückgeben. Wenn Sie eine Referenz zurückgeben möchten, müssen Sie dies als Teil des Rückgabetyps angeben:

std::vector<int> my_func(); // returns value
std::vector<int>& my_func(); // returns reference
std::vector<int> const& my_func(); // returns constant reference

Alle lokalen (Stapel-) Variablen, die innerhalb einer Funktion erstellt wurden, werden zerstört, wenn die Funktion zurückgegeben wird. Das bedeutet, dass Sie die Einheimischen auf keinen Fall als Referenz oder als Konstantenreferenz (oder als Zeiger darauf) zurückgeben sollten. Wenn Sie den Vektor als Wert zurückgeben, wird er möglicherweise kopiert, bevor der lokale Wert zerstört wird, was kostspielig sein kann. (Bestimmte Arten von Optimierungen, die als "Rückgabewertoptimierung" bezeichnet werden, können die Kopie manchmal entfernen. Dies steht jedoch nicht im Rahmen dieser Frage. Es ist nicht immer einfach zu sagen, ob die Optimierung für ein bestimmtes Codeteil durchgeführt wird.)

Wenn Sie einen großen Vektor innerhalb einer Funktion "erstellen" und ihn dann ohne Kopieren zurückgeben möchten, besteht die einfachste Möglichkeit darin, den Vektor als Referenzparameter an die Funktion zu übergeben:

void fill_vector(std::vector<int> &vec) {
    // fill "vec" and don't return anything...
}

Beachten Sie auch, dass in der kürzlich ratifizierten neuen Version des C++ - Standards (bekannt als C++ 0x oder C++ 11) das Zurückgeben eines lokalen Vektors nach Wert von einer Funktion den Vektor nicht tatsächlich kopiert, sondern effizient ist zog an seinen neuen Standort. Der Code, der dies tut, sieht identisch aus wie Code aus früheren Versionen von C++, die gezwungen werden könnten, den Vektor zu kopieren. Erkundigen Sie sich bei Ihrem Compiler, ob er "Verschiebungssemantik" unterstützt (der Teil des C++ 11-Standards, der dies ermöglicht).

2
SoapBox

Wie die meisten Dinge in C++ lautet die Antwort "es hängt davon ab, wie Sie die Funktion definiert haben".

Die Standardeinstellung für die Sprache ist return-by-value. Ein einfacher Aufruf wie "double f ()" gibt immer die Gleitkommazahl als Wert zurück. Sie KÖNNEN jedoch Werte per Zeiger oder Referenz zurückgeben. Fügen Sie einfach die zusätzlichen Symbole '&' oder '*' zum Rückgabetyp hinzu:

// Return by pointer (*)
T* f();

// Return by reference (a single '&')
T& f();

Diese sind jedoch in vielen Situationen lächerlich unsicher. Wenn der Wert, den die Funktion zurückgibt, in der Funktion deklariert wurde, zeigt der zurückgegebene Verweis oder Zeiger statt auf gültige Daten auf zufälligen Müll. Auch wenn Sie garantieren können, dass die Daten, auf die verwiesen wird, immer noch vorhanden sind, ist diese Art der Rückgabe in der Regel schwieriger als es sich lohnt, da alle modernen C++ - Compiler Optimierungen für Sie vornehmen. Die idiomatische und sichere Möglichkeit, etwas als Referenz zurückzugeben, besteht darin, eine benannte Referenz als Parameter zu übergeben:

// Return by 'parameter' (a logical reference return)
void f(T& output);

Jetzt hat der Ausgang einen echten Namen und wir WISSEN, dass er den Aufruf überlebt, da er existieren muss, bevor der Aufruf von 'f' überhaupt erfolgt. Dies ist ein Muster, das Sie in C++ häufig sehen werden, insbesondere für das Auffüllen eines STL-std :: -Vektors. Es ist hässlich, aber bis zum Aufkommen von C++ 11 war es oft schneller als einfach den Vektor nach Wert zurückzugeben. Da die Rückgabe nach Wert auch für viele komplexe Typen einfacher und schneller ist, werden Sie wahrscheinlich nicht viele Funktionen sehen, die dem Referenz-Rückgabeparametermuster außerhalb älterer Bibliotheken folgen.

0
Zack Yezek