Wie kommt es, dass eine nicht konstante Referenz nicht an ein temporäres Objekt gebunden werden kann?

226

Warum ist es nicht erlaubt, eine nicht konstante Referenz auf ein temporäres Objekt zu erhalten, welche Funktion getx()zurückgibt? Dies ist natürlich durch C ++ Standard verboten, aber ich interessiere mich für den Zweck einer solchen Einschränkung, nicht für einen Verweis auf den Standard.

struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}    

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}
  1. Es ist klar, dass die Lebensdauer des Objekts nicht die Ursache sein kann, da eine ständige Bezugnahme auf ein Objekt nicht verboten ist durch C ++ Standard .
  2. Es ist klar, dass das temporäre Objekt im obigen Beispiel nicht konstant ist, da Aufrufe nicht konstanter Funktionen zulässig sind. Zum Beispiel,ref() könnte das temporäre Objekt geändert werden.
  3. Darüber hinaus ref()können Sie den Compiler täuschen und einen Link zu diesem temporären Objekt erhalten , wodurch unser Problem gelöst wird.

Zusätzlich:

Sie sagen, dass "das Zuweisen eines temporären Objekts zur const-Referenz die Lebensdauer dieses Objekts verlängert" und "über nicht-const-Referenzen wird jedoch nichts gesagt". Meine zusätzliche Frage . Verlängert die folgende Zuweisung die Lebensdauer des temporären Objekts?

X& x = getx().ref(); // OK
Alexey Malistov
quelle
4
Ich bin nicht einverstanden mit dem Teil "Die Lebensdauer des Objekts kann nicht die Ursache sein", nur weil im Standard angegeben ist, dass das Zuweisen eines temporären Objekts zur const-Referenz die Lebensdauer dieses Objekts zur Lebensdauer der const-Referenz verlängert. Über nicht
konstante
3
Nun, was ist die Ursache dafür? "Über nicht konstante Referenzen wird jedoch nichts gesagt ...". Es ist ein Teil meiner Frage. Gibt es irgendeinen Sinn darin? Vielleicht haben Autoren von Standard gerade nicht-konstante Referenzen vergessen und bald sehen wir die nächste Kernausgabe?
Alexey Malistov
2
GotW # 88: Ein Kandidat für die "wichtigste Konstante". herbsutter.spaces.live.com/blog/cns!2D4327CC297151BB!378.entry
fnieto - Fernando Nieto
4
@Michael: VC bindet r-Werte an nicht konstante Referenzen. Sie nennen dies eine Funktion, aber es ist wirklich ein Fehler. (Beachten Sie, dass es kein Fehler ist, weil es von Natur aus unlogisch ist, sondern weil es explizit ausgeschlossen wurde, um dumme Fehler zu verhindern.)
sbi

Antworten:

97

Aus diesem Visual C ++ - Blogartikel über rWertreferenzen :

... C ++ möchte nicht, dass Sie versehentlich temporäre Elemente ändern, aber das direkte Aufrufen einer nicht konstanten Elementfunktion für einen veränderbaren r-Wert ist explizit, daher ist es zulässig ...

Grundsätzlich sollten Sie nicht versuchen, temporäre Objekte zu ändern, da sie temporäre Objekte sind und jeden Moment sterben werden. Der Grund, warum Sie nicht-const-Methoden aufrufen dürfen, ist, dass Sie gerne einige "dumme" Dinge tun können, solange Sie wissen, was Sie tun, und dies explizit tun (z. B. mit reinterpret_cast). Wenn Sie jedoch eine temporäre Referenz an eine nicht konstante Referenz binden, können Sie sie "für immer" weitergeben, damit Ihre Manipulation des Objekts verschwindet, da Sie irgendwo auf dem Weg völlig vergessen haben, dass dies eine temporäre Referenz war.

Wenn ich Sie wäre, würde ich das Design meiner Funktionen überdenken. Warum akzeptiert g () eine Referenz, ändert es den Parameter? Wenn nein, machen Sie es zu einem konstanten Verweis. Wenn ja, warum versuchen Sie, es vorübergehend zu übergeben? Ist es Ihnen egal, dass es sich um ein temporäres Element handelt, das Sie ändern? Warum kehrt getx () überhaupt vorübergehend zurück? Wenn Sie uns Ihr reales Szenario und das, was Sie erreichen möchten, mitteilen, erhalten Sie möglicherweise einige gute Vorschläge dazu.

Gegen die Sprache zu gehen und den Compiler zu täuschen, löst selten Probleme - normalerweise entstehen Probleme.


Bearbeiten: Fragen im Kommentar beantworten: 1) X& x = getx().ref(); // OK when will x die? - Ich weiß es nicht und es ist mir egal, denn genau das meine ich mit "gegen die Sprache gehen". In der Sprache heißt es: "Provisorien sterben am Ende der Aussage, es sei denn, sie sind an eine konstante Referenz gebunden. In diesem Fall sterben sie, wenn die Referenz außerhalb des Geltungsbereichs liegt." Bei Anwendung dieser Regel scheint x bereits zu Beginn der nächsten Anweisung tot zu sein, da es nicht an die const-Referenz gebunden ist (der Compiler weiß nicht, was ref () zurückgibt). Dies ist jedoch nur eine Vermutung.

2) Ich habe den Zweck klar angegeben: Sie dürfen keine temporären Elemente ändern, da dies einfach keinen Sinn ergibt (Ignorieren von C ++ 0x-Wertreferenzen). Die Frage "Warum darf ich dann Nicht-Konstanten-Mitglieder anrufen?" ist eine gute, aber ich habe keine bessere Antwort als die, die ich oben bereits angegeben habe.

3) Nun, wenn ich mit x X& x = getx().ref();am Ende der Aussage Recht habe , liegen die Probleme auf der Hand.

Aufgrund Ihrer Fragen und Kommentare denke ich nicht, dass selbst diese zusätzlichen Antworten Sie zufriedenstellen werden. Hier ist ein letzter Versuch / eine letzte Zusammenfassung: Das C ++ - Komitee entschied, dass es nicht sinnvoll ist, temporäre Elemente zu ändern, weshalb die Bindung an nicht konstante Verweise nicht zulässig war. Möglicherweise waren auch einige Compiler-Implementierungen oder historische Probleme beteiligt, ich weiß es nicht. Dann tauchte ein spezifischer Fall auf, und es wurde entschieden, dass sie trotz aller Widrigkeiten weiterhin eine direkte Änderung durch Aufrufen der Nicht-Konstanten-Methode ermöglichen. Dies ist jedoch eine Ausnahme. Sie dürfen temporäre Dateien im Allgemeinen nicht ändern. Ja, C ++ ist oft so komisch.

sbk
quelle
2
@sbk: 1) Eigentlich lautet der richtige Satz: "... am Ende des vollständigen Ausdrucks ...". Ich glaube, ein "vollständiger Ausdruck" ist definiert als einer, der kein Unterausdruck eines anderen Ausdrucks ist. Ob dies immer dasselbe ist wie "das Ende der Aussage", weiß ich nicht genau.
sbi
5
@sbk: 2) Eigentlich Sie sind erlaubt rvalues (Provisorien) zu ändern. Es ist für eingebaute Typen ( intusw.) verboten , für benutzerdefinierte Typen jedoch zulässig : (std::string("A")+"B").append("C").
sbi
6
@sbk: 3) Der Grund, den Stroustrup (in D & E) für die Nichtzulassung der Bindung von r-Werten an nicht konstante Referenzen angibt, ist, dass Alexey g()das Objekt ändern würde (was Sie von einer Funktion erwarten würden, die eine nicht konstante Referenz verwendet). es würde ein Objekt modifizieren, das sterben wird, so dass sowieso niemand den geänderten Wert erreichen könnte. Er sagt, dass dies höchstwahrscheinlich ein Fehler ist.
sbi
2
@sbk: Es tut mir leid, wenn ich dich beleidigt habe, aber ich glaube nicht, dass 2) nicht pickt. R-Werte sind einfach nicht const, es sei denn, Sie machen sie so und Sie können sie ändern, es sei denn, sie sind eingebaut. Es hat eine Weile gedauert, bis ich verstanden habe, ob ich beispielsweise mit dem String-Beispiel etwas falsch mache (JFTR: Ich nicht), daher neige ich dazu, diese Unterscheidung ernst zu nehmen.
sbi
5
Ich stimme sbi zu - diese Angelegenheit ist überhaupt nicht pingelig. Es ist die Grundlage der Verschiebungssemantik, dass r-Werte vom Klassentyp am besten nicht konstant gehalten werden.
Johannes Schaub - Litb
38

In Ihrem Code wird getx()ein temporäres Objekt zurückgegeben, ein sogenannter "rvalue". Sie können r-Werte in Objekte (auch als Variablen bezeichnet) kopieren oder an konstante Referenzen binden (wodurch sich ihre Lebensdauer bis zum Ende der Lebensdauer der Referenz verlängert). Sie können r-Werte nicht an nicht konstante Referenzen binden.

Dies war eine bewusste Entwurfsentscheidung, um zu verhindern, dass Benutzer versehentlich ein Objekt ändern, das am Ende des Ausdrucks sterben wird:

g(getx()); // g() would modify an object without anyone being able to observe

Wenn Sie dies tun möchten, müssen Sie entweder zuerst eine lokale Kopie oder das Objekt erstellen oder es an eine konstante Referenz binden:

X x1 = getx();
const X& x2 = getx(); // extend lifetime of temporary to lifetime of const reference

g(x1); // fine
g(x2); // can't bind a const reference to a non-const reference

Beachten Sie, dass der nächste C ++ - Standard rWertreferenzen enthält. Was Sie als Referenzen kennen, wird daher als "Wertreferenzen" bezeichnet. Sie können rvalues ​​an rvalue-Referenzen binden und Funktionen für "rvalue-ness" überladen:

void g(X&);   // #1, takes an ordinary (lvalue) reference
void g(X&&);  // #2, takes an rvalue reference

X x; 
g(x);      // calls #1
g(getx()); // calls #2
g(X());    // calls #2, too

Die Idee hinter rvalue-Referenzen ist, dass Sie, da diese Objekte sowieso sterben werden, dieses Wissen nutzen und die sogenannte "Verschiebungssemantik" implementieren können, eine bestimmte Art der Optimierung:

class X {
  X(X&& rhs)
    : pimpl( rhs.pimpl ) // steal rhs' data...
  {
    rhs.pimpl = NULL; // ...and leave it empty, but deconstructible
  }

  data* pimpl; // you would use a smart ptr, of course
};


X x(getx()); // x will steal the rvalue's data, leaving the temporary object empty
sbi
quelle
2
Hallo, das ist eine großartige Antwort. Müssen Sie eines wissen, das g(getx())funktioniert nicht, weil seine Signatur ein temporäres Objekt ist g(X& x)und es get(x)zurückgibt, sodass wir ein temporäres Objekt ( rvalue ) nicht an eine nicht konstante Referenz binden können , richtig? Und in Ihrem ersten const X& x2 = getx();const X& x1 = getx();
Codestück
1
Vielen Dank, dass Sie 5 Jahre nach dem Schreiben in meiner Antwort auf diesen Fehler hingewiesen haben! :-/Ja, Ihre Argumentation ist richtig, wenn auch etwas rückwärts: Wir können keine temporären constVerweise an Nicht- (Wert-) Referenzen binden , und daher kann die von getx()(und nicht get(x)) zurückgegebene temporäre Referenz nicht an die Wertreferenz gebunden werden, für die das Argument ist g().
sbi
Ähm, was hast du damit gemeint getx()(und nicht get(x)) ?
SexyBeast
Wenn ich "... getx () (und nicht get (x)) ..." schreibe , meine ich, dass der Name der Funktion lautet getx()und nicht get(x)(wie Sie geschrieben haben).
sbi
Diese Antwort verwechselt die Terminologie. Ein rWert ist eine Ausdruckskategorie. Ein temporäres Objekt ist ein Objekt. Ein Wert kann ein temporäres Objekt bezeichnen oder nicht; und ein temporäres Objekt kann durch einen r-Wert bezeichnet werden oder nicht.
MM
16

Was Sie zeigen, ist, dass die Verkettung von Operatoren zulässig ist.

 X& x = getx().ref(); // OK

Der Ausdruck lautet 'getx (). Ref ();' und dies wird vor der Zuweisung zu 'x' vollständig ausgeführt.

Beachten Sie, dass getx () keine Referenz, sondern ein vollständig geformtes Objekt in den lokalen Kontext zurückgibt. Das Objekt ist temporär, aber nicht const, sodass Sie andere Methoden aufrufen können, um einen Wert zu berechnen, oder andere Nebenwirkungen auftreten können.

// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);

// or more commonly
std::cout << getManiplator() << 5;

Schauen Sie sich das Ende dieser Antwort an, um ein besseres Beispiel dafür zu finden

Sie können eine temporäre Referenz nicht an eine Referenz binden, da dadurch eine Referenz auf ein Objekt generiert wird, das am Ende des Ausdrucks zerstört wird, sodass Sie eine baumelnde Referenz erhalten (die unordentlich ist und der Standard nicht unordentlich mag).

Der von ref () zurückgegebene Wert ist eine gültige Referenz, die Methode berücksichtigt jedoch nicht die Lebensdauer des zurückgegebenen Objekts (da diese Informationen nicht in ihrem Kontext enthalten sein können). Sie haben im Grunde nur das Äquivalent von getan:

x& = const_cast<x&>(getX());

Der Grund, warum es in Ordnung ist, dies mit einer konstanten Referenz auf ein temporäres Objekt zu tun, besteht darin, dass der Standard die Lebensdauer des temporären Objekts auf die Lebensdauer der Referenz verlängert, sodass die Lebensdauer der temporären Objekte über das Ende der Anweisung hinaus verlängert wird.

Die einzig verbleibende Frage ist also, warum der Standard nicht zulassen möchte, dass Verweise auf Provisorien die Lebensdauer des Objekts über das Ende der Aussage hinaus verlängern.

Ich glaube, das liegt daran, dass es dem Compiler sehr schwer fallen würde, temporäre Objekte zu korrigieren. Dies wurde für konstante Verweise auf temporäre Elemente durchgeführt, da dies nur eine begrenzte Verwendung hat und Sie daher gezwungen sind, eine Kopie des Objekts zu erstellen, um etwas Nützliches zu tun, das jedoch einige eingeschränkte Funktionen bietet.

Denken Sie an diese Situation:

int getI() { return 5;}
int x& = getI();

x++; // Note x is an alias to a variable. What variable are you updating.

Die Verlängerung der Lebensdauer dieses temporären Objekts wird sehr verwirrend sein.
Während der folgenden:

int const& y = getI();

Gibt Ihnen Code, der intuitiv zu bedienen und zu verstehen ist.

Wenn Sie den Wert ändern möchten, sollten Sie den Wert an eine Variable zurückgeben. Wenn Sie versuchen, die Kosten für das Zurückkopieren des Objekts aus der Funktion zu vermeiden (da das Objekt anscheinend kopiert wurde (technisch gesehen)). Dann stören Sie sich nicht, der Compiler ist sehr gut in 'Rückgabewertoptimierung'

Martin York
quelle
3
"Die einzige verbleibende Frage ist also, warum der Standard nicht zulassen möchte, dass Verweise auf Provisorien die Lebensdauer des Objekts über das Ende der Aussage hinaus verlängern." Das ist es! Du verstehst meine Frage. Aber ich bin mit Ihrer Meinung nicht einverstanden. Sie sagen "Machen Sie den Compiler sehr schwer", aber es wurde als Konstantenreferenz gemacht. Sie sagen in Ihrem Beispiel: "Hinweis x ist ein Alias ​​für eine Variable. Welche Variable aktualisieren Sie?" Kein Problem. Es gibt eine eindeutige Variable (temporär). Einige temporäre Objekte (gleich 5) müssen geändert werden.
Alexey Malistov
@ Martin: Baumelnde Referenzen sind nicht nur unordentlich. Sie können zu schwerwiegenden Fehlern führen, wenn später in der Methode darauf zugegriffen wird!
mmmmmmmm
1
@Alexey: Beachten Sie, dass die Tatsache, dass das Binden an eine const-Referenz die Lebensdauer eines Temporärs verlängert, eine Ausnahme ist , die absichtlich hinzugefügt wurde (TTBOMK, um manuelle Optimierungen zu ermöglichen). Es wurde keine Ausnahme für nicht konstante Referenzen hinzugefügt, da das Binden einer temporären an eine nicht konstante Referenz höchstwahrscheinlich ein Programmiererfehler war.
sbi
1
@alexy: Ein Verweis auf eine unsichtbare Variable! Nicht so intuitiv.
Martin York
const_cast<x&>(getX());macht keinen Sinn
neugieriger Kerl
10

Warum wird in den C ++ - FAQ ( fettgedruckte Mine) erläutert :

In C ++ können nicht konstante Referenzen an l-Werte und const-Referenzen an l-Werte oder r-Werte binden, aber es gibt nichts, was an einen nicht-konstanten r-Wert gebunden werden kann. Dies soll Menschen davor schützen, die Werte von Zeiträumen zu ändern, die zerstört werden, bevor ihr neuer Wert verwendet werden kann . Beispielsweise:

void incr(int& a) { ++a; }
int i = 0;
incr(i);    // i becomes 1
incr(0);    // error: 0 is not an lvalue

Wenn dieses Inkr (0) entweder vorübergehend wäre, was niemand jemals gesehen hat, würde es inkrementiert werden, oder - weitaus schlimmer - der Wert 0 würde 1 werden. Letzteres klingt albern, aber es gab tatsächlich einen solchen Fehler in frühen Fortran-Compilern, die gesetzt wurden beiseite einen Speicherplatz, um den Wert 0 zu halten.

Tony Delroy
quelle
Es wäre lustig gewesen, das Gesicht des Programmierers zu sehen, der von diesem Fortran "Zero Bug" gebissen wurde! x * 0 gibt x? Was? Was??
John D
Das letzte Argument ist besonders schwach. Kein erwähnenswerter Compiler würde jemals den Wert von 0 in 1 ändern oder sogar so interpretieren incr(0);. Wenn dies erlaubt wäre, würde es offensichtlich so interpretiert, dass eine temporäre Ganzzahl erstellt und anincr()
user3204459
6

Das Hauptproblem ist das

g(getx()); //error

ist ein logischer Fehler: gÄndert das Ergebnis von, getx()aber Sie haben keine Chance, das geänderte Objekt zu untersuchen. Wenn gder Parameter nicht geändert werden müsste, wäre keine lvalue-Referenz erforderlich gewesen. Er hätte den Parameter nach Wert oder nach const-Referenz nehmen können.

const X& x = getx(); // OK

ist gültig, weil Sie manchmal das Ergebnis eines Ausdrucks wiederverwenden müssen und es ziemlich klar ist, dass Sie es mit einem temporären Objekt zu tun haben.

Es ist jedoch nicht möglich zu machen

X& x = getx(); // error

gültig ohne gültig zu machen g(getx()), was die Sprachdesigner zunächst zu vermeiden versuchten.

g(getx().ref()); //OK

ist gültig, weil Methoden nur über die thisKonstanz von Bescheid wissen und nicht wissen, ob sie für einen l-Wert oder einen r-Wert aufgerufen werden.

Wie immer in C ++ haben Sie eine Problemumgehung für diese Regel, aber Sie müssen dem Compiler signalisieren, dass Sie wissen, was Sie tun, indem Sie explizit angeben:

g(const_cast<x&>(getX()));
Dan Berindei
quelle
5

Scheint wie die ursprüngliche Frage zu warum dies nicht zulässig ist, eindeutig beantwortet worden zu sein: "Weil es höchstwahrscheinlich ein Fehler ist".

FWIW, ich dachte ich würde es zeigen wie es geht, obwohl ich nicht denke, dass es eine gute Technik ist.

Der Grund, warum ich manchmal eine temporäre Methode an eine Methode übergeben möchte, die eine nicht konstante Referenz verwendet, besteht darin, absichtlich einen von der Referenz zurückgegebenen Wert wegzuwerfen, den die aufrufende Methode nicht interessiert. Etwas wie das:

// Assuming: void Person::GetNameAndAddr(std::string &name, std::string &addr);
string name;
person.GetNameAndAddr(name, string()); // don't care about addr

Wie in den vorherigen Antworten erläutert, wird dies nicht kompiliert. Aber das kompiliert und funktioniert korrekt (mit meinem Compiler):

person.GetNameAndAddr(name,
    const_cast<string &>(static_cast<const string &>(string())));

Dies zeigt nur, dass Sie Casting verwenden können, um den Compiler anzulügen. Offensichtlich wäre es viel sauberer, eine nicht verwendete automatische Variable zu deklarieren und zu übergeben:

string name;
string unused;
person.GetNameAndAddr(name, unused); // don't care about addr

Diese Technik führt eine nicht benötigte lokale Variable in den Anwendungsbereich der Methode ein. Wenn Sie aus irgendeinem Grund verhindern möchten, dass es später in der Methode verwendet wird, z. B. um Verwirrung oder Fehler zu vermeiden, können Sie es in einem lokalen Block ausblenden:

string name;
{
    string unused;
    person.GetNameAndAddr(name, unused); // don't care about addr
}

- Chris

Chris Pearson
quelle
4

Warum würdest du jemals wollen X& x = getx();? Verwenden Sie einfach X x = getx();RVO und verlassen Sie sich darauf.

DevFred
quelle
3
Weil ich g(getx())lieber anrufen möchte alsg(getx().ref())
Alexey Malistov
4
@ Alexander, das ist kein wirklicher Grund. Wenn Sie das tun, haben Sie überall einen logischen Fehler, weil gSie etwas ändern werden, das Sie nicht mehr in die Hände bekommen können.
Johannes Schaub - litb
3
@ JohannesSchaub-litb vielleicht ist es ihm egal.
Neugieriger
" Verlassen Sie sich auf RVO ", außer es heißt nicht "RVO".
neugieriger Kerl
2
@curiousguy: Das ist ein sehr akzeptierter Begriff dafür. Es ist absolut nichts Falsches daran, es als "RVO" zu bezeichnen.
Welpe
4

Die böse Problemumgehung beinhaltet das Schlüsselwort "veränderlich". Das Böse zu sein, bleibt dem Leser als Übung überlassen. Oder sehen Sie hier: http://www.ddj.com/cpp/184403758

paul
quelle
3

Ausgezeichnete Frage, und hier ist mein Versuch, eine präzisere Antwort zu finden (da viele nützliche Informationen in Kommentaren enthalten sind und sich im Lärm nur schwer ausgraben lassen.)

Jeder Verweis, der direkt an ein Temporär gebunden ist , verlängert dessen Lebensdauer [12.2.5]. Auf der anderen Seite wird eine mit einer anderen Referenz initialisierte Referenz nicht (auch wenn es sich letztendlich um dieselbe temporäre Referenz handelt ). Das ist sinnvoll (der Compiler weiß nicht, worauf sich diese Referenz letztendlich bezieht).

Aber diese ganze Idee ist äußerst verwirrend. ZB const X &x = X();wird das Temporäre so lange dauern wie die xReferenz, aber const X &x = X().ref();NICHT (wer weiß, was ref()tatsächlich zurückgegeben wurde). Im letzteren Fall wird der Destruktor für Xam Ende dieser Zeile aufgerufen. (Dies ist mit einem nicht trivialen Destruktor zu beobachten.)

Es scheint also im Allgemeinen verwirrend und gefährlich zu sein (warum die Regeln für die Lebensdauer von Objekten komplizieren?), Aber vermutlich waren zumindest konstante Referenzen erforderlich, sodass der Standard dieses Verhalten für sie festlegt.

[Aus dem sbi- Kommentar]: Beachten Sie, dass die Tatsache, dass das Binden an eine const-Referenz die Lebensdauer eines Temporärs verlängert, eine Ausnahme ist, die absichtlich hinzugefügt wurde (TTBOMK, um manuelle Optimierungen zu ermöglichen). Es wurde keine Ausnahme für nicht konstante Referenzen hinzugefügt, da das Binden einer temporären an eine nicht konstante Referenz höchstwahrscheinlich ein Programmiererfehler war.

Alle Provisorien bleiben bis zum Ende des vollständigen Ausdrucks bestehen. Um sie nutzen zu können, benötigen Sie jedoch einen Trick, mit dem Sie arbeiten ref(). Das ist legal. Es scheint keinen guten Grund zu geben, durch den zusätzlichen Rahmen zu springen, außer den Programmierer daran zu erinnern, dass etwas Ungewöhnliches vor sich geht (nämlich ein Referenzparameter, dessen Änderungen schnell verloren gehen).

[Ein weiterer sbi- Kommentar] Der Grund, den Stroustrup (in D & E) für die Nichtzulassung der Bindung von r-Werten an nicht konstante Referenzen angibt, ist, dass Alexeys g () das Objekt modifizieren würde (was Sie von einer Funktion erwarten würden, die eine nicht konstante nimmt) Referenz), es würde ein Objekt modifizieren, das sterben wird, so dass sowieso niemand den geänderten Wert erreichen könnte. Er sagt, dass dies höchstwahrscheinlich ein Fehler ist.

DS.
quelle
2

"Es ist klar, dass das temporäre Objekt im obigen Beispiel nicht konstant ist, da Aufrufe nicht konstanter Funktionen zulässig sind. Beispielsweise könnte ref () das temporäre Objekt ändern."

In Ihrem Beispiel gibt getX () keine const X zurück, sodass Sie ref () auf die gleiche Weise aufrufen können wie X (). Ref (). Sie geben eine Nicht-Konstanten-Referenz zurück und können daher Nicht-Konstanten-Methoden aufrufen. Sie können die Referenz jedoch nicht einer Nicht-Konstanten-Referenz zuweisen.

Zusammen mit dem SadSidos-Kommentar macht dies Ihre drei Punkte falsch.

Patrick
quelle
1

Ich möchte ein Szenario mitteilen, in dem ich gerne tun könnte, was Alexey verlangt. In einem Maya C ++ - Plugin muss ich den folgenden Shenanigan ausführen, um einen Wert in ein Knotenattribut zu erhalten:

MFnDoubleArrayData myArrayData;
MObject myArrayObj = myArrayData.create(myArray);   
MPlug myPlug = myNode.findPlug(attributeName);
myPlug.setValue(myArrayObj);

Das Schreiben ist mühsam, daher habe ich die folgenden Hilfsfunktionen geschrieben:

MPlug operator | (MFnDependencyNode& node, MObject& attribute){
    MStatus status;
    MPlug returnValue = node.findPlug(attribute, &status);
    return returnValue;
}

void operator << (MPlug& plug, MDoubleArray& doubleArray){
    MStatus status;
    MFnDoubleArrayData doubleArrayData;
    MObject doubleArrayObject = doubleArrayData.create(doubleArray, &status);
    status = plug.setValue(doubleArrayObject);
}

Und jetzt kann ich den Code vom Anfang des Beitrags schreiben als:

(myNode | attributeName) << myArray;

Das Problem ist, dass es nicht außerhalb von Visual C ++ kompiliert wird, da versucht wird, die vom | zurückgegebene temporäre Variable zu binden Operator zur MPlug-Referenz des Operators <<. Ich möchte, dass es eine Referenz ist, da dieser Code oft aufgerufen wird und ich lieber nicht möchte, dass MPlug so oft kopiert wird. Ich brauche nur das temporäre Objekt, um bis zum Ende der zweiten Funktion zu leben.

Nun, das ist mein Szenario. Ich dachte nur, ich würde ein Beispiel zeigen, wo man das tun möchte, was Alexey beschreibt. Ich freue mich über alle Kritiken und Vorschläge!

Vielen Dank.

Robert Trussardi
quelle