Beim Lesen dieser Erklärung zu lWerten und rWerten fielen mir diese Codezeilen auf:
int& foo();
foo() = 42; // OK, foo() is an lvalue
Ich habe es in g ++ versucht, aber der Compiler sagt "undefinierter Verweis auf foo ()". Wenn ich hinzufüge
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
Es wird gut kompiliert, aber das Ausführen führt zu einem Segmentierungsfehler . Nur die Linie
int& foo();
von selbst kompiliert und läuft ohne Probleme.
Was bedeutet dieser Code? Wie können Sie einem Funktionsaufruf einen Wert zuweisen und warum ist es kein r-Wert?
c++
function
return-by-reference
Sossisos
quelle
quelle
Antworten:
Die Erklärung geht davon aus, dass es eine vernünftige Implementierung gibt, für
foo
die eine l-Wert-Referenz auf eine gültige zurückgegeben wirdint
.Eine solche Implementierung könnte sein:
Da nun
foo
eine lvalue-Referenz zurückgegeben wird, können wir dem Rückgabewert Folgendes zuweisen:Dadurch wird der globale
a
Wert mit dem Wert aktualisiert42
, den wir überprüfen können, indem wir direkt auf die Variable zugreifen oderfoo
erneut aufrufen :quelle
Alle anderen Antworten deklarieren eine Statik innerhalb der Funktion. Ich denke, das könnte Sie verwirren. Schauen Sie sich das an:
Da
highest()
eine Referenz zurückgegeben wird, können Sie ihr einen Wert zuweisen. Wenn dies ausgeführt wird,b
wird es auf 11 geändert. Wenn Sie die Initialisierung so geändert habena
, dass sie beispielsweise 8 war, wirda
sie auf 11 geändert. Dies ist ein Code, der im Gegensatz zu den anderen Beispielen möglicherweise tatsächlich einen Zweck erfüllt.quelle
Deklariert eine Funktion namens foo, die einen Verweis auf a zurückgibt
int
. Was diese Beispiele nicht tun, ist, Ihnen eine Definition dieser Funktion zu geben, die Sie kompilieren könnten. Wenn wir verwendenJetzt haben wir eine Funktion, die einen Verweis auf zurückgibt
bar
. da bar iststatic
, wird es nach dem Aufruf der Funktion weiterleben, so dass die Rückgabe eines Verweises darauf sicher ist. Wenn wir das tunWas passiert, ist, dass wir 42 zuweisen,
bar
da wir der Referenz zuweisen und die Referenz nur ein Alias für istbar
. Rufen wir die Funktion nochmal gerne aufEs würde 42 drucken, da wir
bar
das oben eingestellt haben.quelle
int &foo();
deklariert eine Funktion, diefoo()
mit dem Rückgabetyp aufgerufen wirdint&
. Wenn Sie diese Funktion aufrufen, ohne einen Text anzugeben, wird wahrscheinlich ein undefinierter Referenzfehler angezeigt.In Ihrem zweiten Versuch haben Sie eine Funktion bereitgestellt
int foo()
. Dies hat einen anderen Rückgabetyp als die von deklarierte Funktionint& foo();
. Sie haben also zwei Deklarationen derselbenfoo
, die nicht übereinstimmen, was gegen die One Definition Rule verstößt und undefiniertes Verhalten verursacht (keine Diagnose erforderlich).Nehmen Sie für etwas, das funktioniert, die lokale Funktionsdeklaration heraus. Sie können zu stillem undefiniertem Verhalten führen, wie Sie gesehen haben. Verwenden Sie stattdessen nur Funktionsdeklarationen außerhalb einer Funktion. Ihr Programm könnte folgendermaßen aussehen:
quelle
int& foo();
ist eine Funktion, die einen Verweis auf zurückgibtint
. Ihre bereitgestellte Funktion wirdint
ohne Referenz zurückgegeben.Sie können tun
quelle
int & foo();
bedeutet, dassfoo()
ein Verweis auf eine Variable zurückgegeben wird.Betrachten Sie diesen Code:
Dieser Code druckt:
$ ./a.out k = 5
Weil
foo()
einen Verweis auf die globale Variable zurückgibtk
.In Ihrem überarbeiteten Code wandeln Sie den zurückgegebenen Wert in eine Referenz um, die dann ungültig ist.
quelle
In diesem Zusammenhang bedeutet & eine Referenz - also gibt foo eine Referenz auf ein int und nicht auf ein int zurück.
Ich bin mir nicht sicher, ob Sie schon mit Zeigern gearbeitet hätten, aber es ist eine ähnliche Idee, dass Sie den Wert nicht tatsächlich aus der Funktion zurückgeben - stattdessen übergeben Sie die Informationen, die erforderlich sind, um den Speicherort im Speicher zu finden, an dem sich dieser befindet int ist.
Zusammenfassend lässt sich sagen, dass Sie einem Funktionsaufruf keinen Wert zuweisen. Sie verwenden eine Funktion, um eine Referenz abzurufen, und weisen dann den Wert, auf den verwiesen wird, einem neuen Wert zu. Es ist leicht zu glauben, dass alles auf einmal passiert, aber in Wirklichkeit erledigt der Computer alles in einer genauen Reihenfolge.
Wenn Sie sich fragen - der Grund, warum Sie einen Segfault erhalten, ist, dass Sie ein numerisches Literal '2' zurückgeben -, ist dies der genaue Fehler, den Sie erhalten würden, wenn Sie einen const int definieren und dann versuchen würden, ihn zu ändern Wert.
Wenn Sie noch nichts über Zeiger und dynamisches Gedächtnis gelernt haben, würde ich dies zunächst empfehlen, da es einige Konzepte gibt, die meiner Meinung nach schwer zu verstehen sind, es sei denn, Sie lernen sie alle gleichzeitig.
quelle
Der Beispielcode auf der verlinkten Seite ist nur eine Dummy-Funktionsdeklaration. Es wird nicht kompiliert, aber wenn Sie eine Funktion definiert hätten, würde es im Allgemeinen funktionieren. Das Beispiel bedeutete "Wenn Sie eine Funktion mit dieser Signatur hätten, könnten Sie sie so verwenden".
In Ihrem Beispiel
foo
wird eindeutig ein l-Wert basierend auf der Signatur zurückgegeben, aber Sie geben einen r-Wert zurück, der in einen l-Wert konvertiert wird. Dies ist eindeutig zum Scheitern verurteilt. Du könntest es tun:und würde erfolgreich sein, indem der Wert von x geändert wird, wenn gesagt wird:
quelle
Die Funktion, die Sie haben, foo (), ist eine Funktion, die einen Verweis auf eine Ganzzahl zurückgibt.
Nehmen wir also an, ursprünglich hat foo 5 zurückgegeben, und später, in Ihrer Hauptfunktion, sagen Sie
foo() = 10;
, druckt dann foo aus, es werden 10 statt 5 gedruckt.Ich hoffe das ergibt Sinn :)
Ich bin auch neu in der Programmierung. Es ist interessant, solche Fragen zu sehen, die zum Nachdenken anregen! :) :)
quelle