Frage

EDIT: Diese Frage ist mehr über die Sprache Engineering als C ++ selbst. Früher habe ich C ++ als ein Beispiel zu zeigen, was ich wollte, vor allem, weil ich es täglich verwenden. Ich wollte nicht wissen, wie es auf C ++ funktioniert aber öffnen Sie eine Diskussion darüber, wie es könnte erfolgen.

Das ist nicht so, wie es jetzt funktioniert, das ist die Art und Weise I Wunsch es getan werden könnte, und das wäre C compability sicher zu brechen, aber das ist, was ich denke extern „C“ dreht sich alles um .

Ich meine, in jeder Funktion oder Methode, die Sie gerade jetzt erklären Sie explizite Schreib haben, dass das Objekt mit Bezug auf den Referenzoperator prefixing gesendet wird. Ich wünsche, dass jeder Nicht-POD-Typ automatisch durch Bezugnahme gesendet werden würde, weil ich, dass eine Menge zu verwenden, tatsächlich für jedes Objekt, das mehr als 32 Bit groß ist, und das ist fast jede Klasse von mir.

Lassen Sie uns erläutern, wie es jetzt ist, übernehmen a b und c Klassen sein:

class example {
    public:
        int just_use_a(const a &object);
        int use_and_mess_with_b(b &object);
        void do_nothing_on_c(c object);
};

Nun, was ich will:

class example {
    public:
        int just_use_a(const a object);
        int use_and_mess_with_b(b object);
        extern "C" void do_nothing_on_c(c object);
};

Nun do_nothing_on_c () könnte sich verhalten wie es heute ist.

Das wäre für mich interessant zumindest sein, fühlt sich viel mehr klar, und auch, wenn Sie wissen jeder Nicht-POD Parameter kommt durch Bezugnahme glaube ich, die Fehler, die gleiche sein würde, wenn Sie hatte expliziter erklärt es.

Ein weiterer Gesichtspunkt für diese Änderung, von jemandem aus C kommen, der Referenz-Operator mir scheint eine Möglichkeit, um die Variable zu bekommen Adresse , das ist die Art, wie ich für immer Zeiger verwendet. Ich meine, es ist der gleiche Betreiber jedoch mit unterschiedlichen semantischen auf unterschiedlichen Kontexten, ist das nicht ein wenig falsch fühlen auch für Sie?

War es hilfreich?

Lösung

Ich denke, man den Punkt C ++ fehlt, und C ++ Semantik. Sie verfehlten die Tatsache, C ++ korrekt ist (fast) alles, was von Wert im Vorbeigehen, weil es die Art und Weise ist es in C. Immer fertig ist. Aber nicht nur in C, wie ich werde Sie unten zeigen ...

Parameter Semantics auf C

In C wird alles von Wert übergeben. „Primitive“ und „PODs“ werden durch das Kopieren von ihrem Wert übergeben. Ändern Sie sie in Ihrer Funktion und das Original wird nicht geändert werden. Dennoch könnten die Kosten einige PODs des Kopierens nicht-trivial.

Wenn Sie die Zeiger-Notation (die *) verwenden, die Sie vorbei nicht Bezug genommen wird. Sie sind vorbei, eine Kopie der Adresse. Welches ist mehr oder weniger die gleiche, mit nur einem kleinen Unterschied:

typedef struct { int value ; } P ;

/* p is a pointer to P */
void doSomethingElse(P * p)
{
   p->value = 32 ;
   p = malloc(sizeof(P)) ; /* Don't bother with the leak */
   p->value = 45 ;
}

void doSomething()
{
   P * p = malloc(sizeof(P)) ;
   p->value = 25 ;

   doSomethingElse(p) ;

     int i = p->value ;
   /* Value of p ? 25 ? 32 ? 42 ? */
}

Der Endwert von p-> Wert ist 32. Da p durch Kopieren des Wertes der Adresse übergeben wurde. So das ursprüngliche p nicht geändert wurde (und die neue durchgesickert war).

Parameter Semantics auf Java und C Sharp

Es kann für einige überraschend sein, aber in Java, alles von Wert, auch kopiert. Das C Beispiel oben würde genau die gleichen Ergebnisse in Java. Das ist fast, was Sie wollen, aber Sie würden nicht in der Lage sein, primitive „durch Verweis / Zeiger“ passieren so leicht wie in C.

In C #, fügten sie hinzu, das "ref" Schlüsselwort. Es funktioniert mehr oder weniger wie die Referenz in C ++. Der Punkt ist, auf C #, Sie haben es sowohl auf der Funktionsdeklaration zu erwähnen, und auf jedem Anruf. Ich denke, das ist nicht das, was Sie wollen, wieder.

Parameter Semantics auf C ++

In C ++, fast alles wird durch Kopieren des Wertes übergeben. Wenn Sie nichts anderes als die Art des Symbols verwenden, sind Kopieren Sie das Symbol (wie es in C der Fall ist). Aus diesem Grund, wenn Sie die * verwenden, sind Sie eine Kopie der Adresse des Symbols vorbei.

Aber wenn man das & verwenden, dann übernehmen Sie das reale Objekt vorbei (sei es struct, int, Zeiger, was auch immer). Der Verweis

Es ist einfach, sie als syntaxic Zucker zu verwechseln (das heißt, hinter den Kulissen, es funktioniert wie ein Zeiger, und der generierte Code ist für einen Zeiger verwendet wird). Aber ...

Die Wahrheit ist, dass die Referenz mehr als syntaxic Zucker.

  • Im Gegensatz zu Zeiger, autorisiert er das Objekt, als ob auf dem Stapel zu manipulieren.
  • Unline Zeiger, wenn sie mit dem Schlüsselwort const associatied autorisiert es implizite Förderung von einem Typ in einen anderen (durch den Bau, vor allem).
  • Im Gegensatz zu Zeiger, wird das Symbol nicht angenommen NULL / ungültig.
  • Im Gegensatz zu den „by-Kopie“, Sie das Objekt nicht verbringen nutzlos Zeit Kopieren
  • Im Gegensatz zu dem "by-Kopie", können Sie es als ein verwenden [out] Parameter
  • Im Gegensatz zu den „by-Kopie“ können Sie das gesamte Spektrum der OOP in C ++ verwenden (das heißt Sie übergeben ein vollständiges Objekt an eine Funktion eine Schnittstelle zu warten).

So, Referenzen hat das Beste aus beiden Welten.

Lassen Sie sich das C Beispiel sehen, aber mit einer C ++ Variation der doSomethingElse Funktion:

struct P { int value ; } ;

// p is a reference to a pointer to P
void doSomethingElse(P * & p)
{
   p->value = 32 ;
   p = (P *) malloc(sizeof(P)) ; // Don't bother with the leak
   p->value = 45 ;
}

void doSomething()
{
   P * p = (P *) malloc(sizeof(P)) ;
   p->value = 25 ;

   doSomethingElse(p) ;

     int i = p->value ;
   // Value of p ? 25 ? 32 ? 42 ?
}

Das Ergebnis ist 42, und die alte p durchgesickert war, durch die neuen p ersetzt. Denn im Gegensatz zu C-Code, wir vorbei nicht eine Kopie des Zeigers, aber den Verweis auf den Zeiger, das heißt, der Zeiger selbst.

Wenn Sie mit C ++ arbeitet, muß das obige Beispiel kristallklar sein. Wenn dies nicht der Fall, dann sind Sie nicht etwas.

Fazit

C ++ ist Pass-by-copy / Wert, weil es die Art und Weise alles funktioniert, sei es in C, in C # oder in Java (auch in JavaScript ... :-P ...). Und wie C #, C ++ hat ein Referenz-Operator / Stichwort, als Bonus .

Nun, soweit ich es verstehe, sind Sie vielleicht tun, was ich als Halb jockingly C + , das heißt, C mit einer begrenzten Anzahl C ++ Funktionen.

Vielleicht ist Ihre Lösung wird typedefs mit (es wird Ihre C ++ Kollegen erzürnen, obwohl, um den Code zu sehen von nutzlos typedefs verschmutzt ...), aber dies tun wird nur die Tatsache verschleiern, sind Sie wirklich C fehlt ++ gibt.

Wie sagte in einem anderen Beitrag, sollten Sie Ihre Einstellung von C Entwicklung ändern (von was auch immer) zu C ++ Entwicklung, oder sollten Sie vielleicht in einer anderen Sprache bewegen. Aber nicht hält den Weg C Programmierung mit C ++ Funktionen, denn durch bewusst ignorieren / Verschleiern der Macht der Idiome Sie verwenden, werden Sie suboptimalen Code erzeugen.

Hinweis: Und geben sie nicht durch irgendetwas anderes als kopieren Primitiven. Sie werden Ihre Funktion von seiner OO Kapazität kastrieren, und in C ++, das ist nicht das, was Sie wollen.

Bearbeiten

Die Frage war etwas geändert (siehe https://stackoverflow.com/revisions/ 146.271 / Liste ). Ich lasse meine ursprüngliche Antwort, und beantworten Sie die neuen Fragen unten.

Was denken Sie über Standard-pass-by-reference Semantik auf C ++? Wie Sie schon sagten, es wäre Kompatibilität zu brechen, und Sie haben verschiedene Pass-by für Primitive (dh integrierten Typen , die immer noch durch Kopie) und structs / Objekte übergeben werden würde (die als Referenzen übergeben werden würde). Sie würden einen anderen Betreiber hinzufügen müssen, bedeutet „Pass-by-Wert“ (die extern „C“ ist ganz schrecklich und schon für etwas verwendet, sonst ganz anders). Nein, ich mag die Art und Weise es heute in C ++ durchgeführt wird.

[...] für den Referenzoperator scheint mir einen Weg, um die Variable-Adresse zu erhalten, das ist die Art, wie ich für immer Zeiger verwendet. Ich meine, es ist der gleiche Betreiber jedoch mit unterschiedlichen semantischen auf unterschiedlichen Kontexten, ist das nicht ein wenig falsch für dich fühlen? Ja und nein. Operator >> änderte seine semantischen wenn mit C ++ Strömen verwendet, auch. Dann können Sie Operator + verwenden = strcat zu ersetzen. Ich denke, der Operator & wurde verwendet, weil seine Bedeutung als „Gegenteil von dem Zeiger“, und weil sie nicht noch ein weiteres Symbol verwenden wollte (ASCII ist begrenzt, und der Umfang Betreiber :: sowie Zeiger -> zeigt, dass einige andere Symbole verwendbar sind). Aber jetzt, wenn & stört Sie, && wirklich verunsichern Sie, da sie eine einstellige && in C ++ 0x (eine Art Super-Referenz ...) hinzugefügt. Ich habe noch es selbst zu verdauen ...

Andere Tipps

Eine Compiler-Option, die völlig die Bedeutung eines Code-Abschnitt ändert klingt wie eine wirklich schlechte Idee zu mir. Entweder verwenden, um die Syntax ++ C zu erhalten oder um eine andere Sprache finden.

Ich möchte lieber nicht Referenzen missbrauchen mehr jeder von jedem (nicht qualifiziert) Herstellung eines Referenzparameter.

Der Hauptgrund Referenzen wurden in C ++ hinzugefügt WAS zu Unterstützung Betreiber Überlastung ; wenn Sie „pass-by-reference“ Semantik wollen, C hatte eine durchaus vernünftige Art und Weise tun. Zeiger

Zeiger Mit deutlich macht Ihre Absicht, den Wert des spitzen Gegenstandes zu ändern, und es ist möglich, dies im Funktionsaufruf der Suche nach nur um zu sehen, Sie müssen nicht in der Funktionsdeklaration sehen, ob es mit einem Bezug genommen wird.

Auch finden Sie unter

  

Ich will das Argument ändern,   soll ich einen Zeiger verwenden, oder soll ich verwenden   eine Referenz? Ich weiß nicht, eine starke   logischer Grund. Wenn vorbei `` nicht ein   Objekt ‚‘ (beispielsweise ein Null-Zeiger) ist   akzeptabel, einen Zeiger unter Verwendung macht   Sinn. Mein persönlicher Stil ist ein zu verwenden,   Zeiger, wenn ich will ein ändern   Objekt, weil in manchen Kontexten, dass   macht es leichter, dass ein beschmutzen   Änderung ist möglich.

aus dem gleichen FAQ .

Ja, ich bin der Meinung, dass das eine ziemlich verwirrend Überlastung ist.

Dies ist, was Microsoft über die Situation zu sagen hat:

  

Verwechseln Sie nicht Verweis Erklärungen unter Verwendung des Adressoperators. Wenn & Identifikator von einem Typ, wie int oder char vorangestellt ist, dann Identifikator wird als Referenz auf die Art erklärt. Wenn & Kennung durch einen Typen nicht vorangeht, ist die Verwendung des den Adressoperator.

Ich bin nicht wirklich auf C oder C ++, aber ich habe größere Kopfschmerzen, die verschiedenen Verwendungen von Aussortieren * und & auf beiden Sprachen als ich in Assembler Kodierung tun.

Der beste Rat ist zu einer Gewohnheit macht darüber nachzudenken, was Sie wirklich passieren wollen. Übergabe als Referenz ist schön, wenn man keine Kopie Konstruktor haben (oder nicht wollen, es zu benutzen) und es ist billiger für große Objekte. Doch dann Mutationen an den Parameter außerhalb der Klasse zu spüren. Sie könnten stattdessen durch const Verweis übergeben - dann gibt es keine Mutationen, aber Sie können nicht lokale Änderungen vornehmen. Pass konst by-Wert für günstige Objekte, die nur schreib in der Funktion werden sollte und nicht-const by-Wert übergeben, wenn Sie eine Kopie anfertigen möchten, dass Sie lokale Änderungen vornehmen können.

Jede Permutation (by-Wert / by-reference und const / nicht-const) wichtige Unterschiede aufweist, die definitiv nicht gleichwertig sind.

Wenn Sie nach Wert übergeben, kopieren Sie die Daten auf den Stapel. Für den Fall, dass Sie einen Operator haben = definiert für die Struktur oder Klasse, dass Sie es sind vorbei, wird sie ausgeführt. Es gibt keine Compiler-Direktive ich weiß davon würde die rigmarole impliziter Sprachverwirrung, dass die vorgeschlagene Änderung von Natur verursachen würde abzuwaschen.

Eine gemeinsame Best Practice ist es, Werte von const Referenz zu übergeben, nicht nur Bezug genommen wird. Dadurch wird sichergestellt, dass der Wert nicht in der aufrufenden Funktion geändert werden. Dies ist ein Element einer const-korrekte Code-Basis.

Eine voll const-korrekte Code-Basis geht noch weiter, Konst bis zum Ende der Prototypen hinzuzufügen. Bedenken Sie:

void Foo::PrintStats( void ) const {
   /* Cannot modify Foo member variables */
}

void Foo::ChangeStats( void ) {
   /* Can modify foo member variables */
}

Wenn Sie in einer Funktion eine Foo-Objekt übergeben waren, mit const Präfix, sind Sie in der Lage printStats () aufrufen. Der Compiler würde Fehler aus auf einen Aufruf von ChangeStats ().

void ManipulateFoo( const Foo &foo )
{
    foo.PrintStats();  // Works
    foo.ChangeStats(); // Oops; compile error
}

Ich denke ehrlich, dass diese ganzen vorbei Wert / vorbei Referenz Idee in C ++ irreführend ist. Alles ist Pass von Wert. Sie haben drei Fälle:

  1. Wenn Sie eine lokale Kopie einer Variablen übergeben

    void myFunct(int cantChangeMyValue)
    
  2. Wenn Sie eine lokale Kopie eines Zeiger auf eine Variable übergeben

    void myFunct(int* cantChangeMyAddress) {
        *cantChangeMyAddress = 10;
    }
    
  3. Wenn Sie eine ‚Referenz‘ bestehen, sondern durch Compiler Magie wie es nur, wenn Sie einen Zeiger übergeben und einfach dereferenziert es jedes Mal.

    void myFunct(int & hereBeMagic) {
        hereBeMagic = 10; // same as 2, without the dereference
    }
    

Ich persönlich finde es viel weniger verwirrend zu erinnern, dass alles Pass von Wert ist. In einigen Fällen kann dieser Wert eine Adresse sein, die Sie Dinge außerhalb der Funktion ändern.

Was Sie vorschlagen würde der Programmierer 1. Ich denke, tun Nummer nicht zulassen, dass persönlich, dass eine schlechte Idee, diese Option zu nehmen wäre. Ein großes Plus von C / C ++ ist mit hat feinkörnige Speicherverwaltung. alles über einen Verweis zu machen ist einfach versuchen, C ++ mehr wie Java zu machen.

gibt es etwas nicht klar. wenn Sie sagen:

  

int b (b & param);

Was haben Sie beabsichtigen, für das zweite ‚b‘? vergessen Sie eine Art einzuführen? Haben Sie vergessen, anders in Bezug auf den ersten ‚b‘ zu schreiben? glauben Sie nicht, es ist klar, so etwas wie zu schreiben:

class B{/*something...*/};
int b(B& param);

Da nun, nehme ich an, dass Sie meinen, was ich schreibe.

Nun, Ihre Frage ist „glaube nicht, dass man besser sein wird, dass die Compiler jeden Pass-by-Wert eines Nicht-POD als Pass-by-ref? Prüfen“. Das erste Problem ist, dass es Ihren Vertrag gebrochen wird. Ich nehme an, Sie meinen Pass-by-CONST-Referenz, und zwar nicht nur Bezug genommen wird.

jetzt Ihre Frage zu diesem reduziert wird: „Sie wissen, ob es einige Compiler-Richtlinie ist, die Funktionsaufruf von Wert optimieren können“

Die Antwort jetzt ist: „Ich weiß nicht“.

Ich denke, dass c ++ wird sehr chaotisch, wenn Sie alle mischen, um die Art des verfügbaren Parameters zu starten, mit ihren konst Variationen.

Es wird schnell aus der Hand trak alle Kopierkonstruktoren Anrufe, alle Dereferenzierungen überlastet und so weiter.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top