c++ - Verwendung von 'const' für Funktionsparameter


Wie weit gehst du mit const ? Machst du einfach Funktionen const wenn nötig oder gehst du das ganze Schwein und verwendest es überall? Stellen Sie sich beispielsweise einen einfachen Mutator vor, der einen einzigen booleschen Parameter verwendet:

void SetValue(const bool b) { my_val_ = b; }

Ist das eigentlich nützlich? Persönlich verwende ich es ausgiebig, einschließlich Parameter, aber in diesem Fall frage ich mich, ob es sich lohnt?

Ich war auch überrascht zu erfahren, dass Sie const von Parametern in einer Funktionsdeklaration weglassen können, sie aber in die Funktionsdefinition aufnehmen können, zB:

.h-Datei

void func(int n, long l);

.cpp-Datei

void func(const int n, const long l)

Gibt es einen Grund dafür? Es scheint ein wenig ungewöhnlich für mich.



Answers



Der Grund dafür ist, dass const für den Parameter nur lokal innerhalb der Funktion gilt, da es an einer Kopie der Daten arbeitet. Das bedeutet, dass die Funktionssignatur sowieso die gleiche ist. Es ist wahrscheinlich ein schlechter Stil, dies zu tun.

Ich persönlich tendiere dazu, const nicht zu verwenden, außer für Referenz- und Zeigerparameter. Für kopierte Objekte spielt es keine Rolle, obwohl es sicherer sein kann, da es Absicht innerhalb der Funktion signalisiert. Es ist wirklich ein Urteilsruf. Ich tendiere jedoch dazu, const_iterator zu verwenden, wenn ich auf etwas schließe, und ich beabsichtige nicht, es zu modifizieren, also schätze ich es jedem selbst zu, solange die const-Korrektheit für Referenztypen rigoros beibehalten wird.




"const ist sinnlos, wenn das Argument per Wert übergeben wird, da Sie das Objekt des Aufrufers nicht ändern werden."

Falsch.

Es geht darum, Ihren Code und Ihre Annahmen selbst zu dokumentieren.

Wenn in Ihrem Code viele Leute daran arbeiten und Ihre Funktionen nicht trivial sind, dann sollten Sie "const" alles markieren, was Sie können. Wenn Sie Code für die industrielle Stärke schreiben, sollten Sie immer davon ausgehen, dass Ihre Mitarbeiter Psychopathen sind, die versuchen, Sie so weit wie möglich zu bekommen (besonders, weil Sie sich in der Zukunft oft selbst gehören).

Außerdem könnte es, wie schon erwähnt, dem Compiler helfen, die Dinge ein wenig zu optimieren (auch wenn es eine lange Sicht ist).




Manchmal (zu oft!) Muss ich den C ++ Code von jemand anderem entwirren. Und wir alle wissen, dass der C ++ - Code einer anderen Person fast per Definition ein kompletter Durcheinander ist :) Das erste, was ich unternehme, um den lokalen Datenfluss zu entschlüsseln, ist const in jeder Variablendefinition, bis der Compiler anfängt zu bellen. Dies bedeutet auch konstante Qualifikationsargumente, da es sich um einfache lokale Variablen handelt, die vom Aufrufer initialisiert werden.

Ah, ich wünschte, Variablen wären standardmäßig const und für nicht konstante Variablen wäre veränderbar :)




Die folgenden zwei Zeilen sind funktionell äquivalent:

int foo (int a);
int foo (const int a);

Offensichtlich werden Sie a im Körper von foo nicht ändern können, wenn es den zweiten Weg definiert, aber es gibt keinen Unterschied von außen.

Wobei const mit den Verweis- oder const wirklich praktisch ist:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

Was das sagt, ist, dass foo einen großen Parameter nehmen kann, vielleicht eine Datenstruktur, die Gigabytes groß ist, ohne sie zu kopieren. Außerdem sagt es dem Anrufer: "Foo wird den Inhalt dieses Parameters nicht ändern." Wenn Sie eine const-Referenz übergeben, kann der Compiler bestimmte Leistungsentscheidungen treffen.

*: Es sei denn es wirft die Konstanz weg, aber das ist ein anderer Beitrag.




Extra-überflüssige const sind von einem API-Standpunkt aus schlecht:

Wenn Sie zusätzliche überflüssige Konstanten in Ihrem Code für vom Parameter übergebene Parameter vom Typ intrinsic übergeben, wird Ihre API blockiert , ohne dass dem Aufrufer oder API-Benutzer ein wichtiges Versprechen gegeben wird (es behindert nur die Implementierung).

Zu viele 'const' in einer API, wenn sie nicht benötigt werden, sind wie " weinender Wolf ", schließlich werden die Leute anfangen, 'const' zu ignorieren, weil sie überall zu finden sind und meistens nichts bedeuten.

Das Argument "reductio ad absurdum" für zusätzliche Konstanten in der API ist gut für diese ersten beiden Punkte wäre, wenn mehr const-Parameter gut sind, dann sollte jedes Argument, das eine const auf ihr haben kann, eine const auf sie haben. In der Tat, wenn es wirklich so gut wäre, würden Sie wollen, dass const der Standardwert für Parameter ist und ein Schlüsselwort wie "mutable" nur dann hat, wenn Sie den Parameter ändern wollen.

Also versuchen wir, const einzubauen, wo immer wir können:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

Betrachten Sie die obige Codezeile. Die Deklaration ist nicht nur unübersichtlicher und länger und schwerer zu lesen, sondern drei der vier "const" -Schlüsselwörter können vom API-Benutzer ignoriert werden. Jedoch hat die zusätzliche Verwendung von 'const' die zweite Zeile potentiell GEFÄHRLICH gemacht!

Warum?

Wenn Sie den ersten Parameter char * const buffer falsch char * const buffer könnten Sie denken, dass der Speicher im übergebenen Datenpuffer nicht geändert wird - dies ist jedoch nicht der Fall! Überflüssiges "const" kann zu gefährlichen und falschen Annahmen über Ihre API führen, wenn sie schnell gescannt oder falsch gelesen werden.

Überflüssige const sind auch von einem Code-Implementierungsstandpunkt aus schlecht:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

Wenn FLEXIBLE_IMPLEMENTATION nicht wahr ist, dann ist die API "vielversprechend", die Funktion auf dem ersten Weg unten nicht zu implementieren.

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

Das ist ein sehr dummes Versprechen. Warum sollten Sie ein Versprechen machen, das Ihrem Anrufer überhaupt keinen Nutzen bringt und nur Ihre Implementierung einschränkt?

Beide sind vollkommen gültige Implementierungen der gleichen Funktion, obwohl alles, was Sie getan haben, eine Hand hinter Ihrem Rücken unnötig gebunden ist.

Darüber hinaus ist es ein sehr oberflächliches Versprechen, das leicht (und rechtlich umgangen) ist.

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

Schauen Sie, ich habe es auf diese Weise irgendwie implementiert, obwohl ich versprochen habe, nicht - nur eine Wrapper-Funktion zu verwenden. Es ist wie wenn der Bösewicht verspricht, jemanden in einem Film nicht zu töten und beauftragt seinen Handlanger, sie stattdessen zu töten.

Diese überflüssigen Const's sind nicht mehr wert als ein Versprechen eines Film-Bösewichts.

Aber die Fähigkeit zu lügen wird noch schlimmer:

Ich habe aufgeklärt, dass Sie const in header (Deklaration) und code (definition) durch Verwendung von spurious const nicht übereinstimmen können. Die Const-happy Befürworter behaupten, dies sei eine gute Sache, da Sie nur in der Definition const setzen können.

// Example of const only in definition, not declaration
class foo { void test(int *pi); };
void foo::test(int * const pi) { }

Die Umkehrung ist jedoch wahr ... Sie können nur in der Deklaration eine falsche Konstante setzen und diese in der Definition ignorieren. Das macht die überflüssige Konstante in einer API eher schrecklich und eine schreckliche Lüge - siehe dieses Beispiel:

class foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

Alles, was überflüssig ist, ist, den Code des Implementierers weniger lesbar zu machen, indem er ihn zwingt, eine andere lokale Kopie oder eine Wrapper-Funktion zu verwenden, wenn er die Variable ändern oder die Variable durch eine Nicht-Konst-Referenz übergeben will.

Schauen Sie sich dieses Beispiel an. Was ist lesbarer? Ist es offensichtlich, dass der einzige Grund für die zusätzliche Variable in der zweiten Funktion ist, weil einige API-Designer eine überflüssige const?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

Hoffentlich haben wir hier etwas gelernt. Überflüssiges Const ist ein API-Durcheinander-Schandfleck, ein lästiger Nörgel, ein oberflächliches und bedeutungsloses Versprechen, ein unnötiges Hindernis und führt gelegentlich zu sehr gefährlichen Fehlern.




const sollte der Standardwert in C ++ gewesen sein. So was :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable



Als ich C ++ für meinen Lebensunterhalt programmierte, habe ich alles bestanden, was ich konnte. Die Verwendung von const ist eine gute Möglichkeit, dem Compiler dabei zu helfen, Ihnen zu helfen. Zum Beispiel kann das Konstanten der Rückgabewerte Ihrer Methode Sie vor Tippfehlern wie:

foo() = 42

wenn du meintest:

foo() == 42

Wenn foo () definiert ist, um eine nicht konstante Referenz zurückzugeben:

int& foo() { /* ... */ }

Der Compiler lässt Ihnen gerne einen Wert an das vom Funktionsaufruf zurückgegebene anonyme Temporär zu. Konstant machen:

const int& foo() { /* ... */ }

Beseitigt diese Möglichkeit.




Eine gute Diskussion zu diesem Thema gibt es in den alten "Guru der Woche" -Artikeln auf comp.lang.c ++. Moderiert hier .

Der entsprechende GOTW-Artikel ist hier auf der Herb Sutter-Website verfügbar.




Ich benutze const auf Funktionsparametern, die Verweisungen (oder Zeiger) sind, die nur [in] Daten sind und nicht durch die Funktion geändert werden. Bedeutung, wenn der Zweck der Verwendung einer Referenz darin besteht, das Kopieren von Daten zu vermeiden und das Ändern des übergebenen Parameters nicht zuzulassen.

Das Setzen von const auf den booleschen b-Parameter in Ihrem Beispiel legt nur eine Einschränkung für die Implementierung fest und trägt nicht zur Schnittstelle der Klasse bei (obwohl normalerweise keine Änderung von Parametern empfohlen wird).

Die Funktionssignatur für

void foo(int a);

und

void foo(const int a);

ist das gleiche, was Ihre .c und .h erklärt

Asaf




Ich sage const Ihre Wertparameter.

Betrachten Sie diese Buggy-Funktion:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

Wenn der Zahlenparameter const wäre, würde der Compiler aufhören und uns vor dem Fehler warnen.




Wenn Sie die Operatoren ->* oder .* Verwenden, ist das ein Muss.

Es hindert Sie daran, etwas wie

void foo(Bar *p) { if (++p->*member > 0) { ... } }

was ich im Moment fast getan habe und das wahrscheinlich nicht das tut, was Sie beabsichtigen.

Was ich sagen wollte, war

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

und wenn ich eine const zwischen Bar * und p hätte, hätte mir der Compiler das gesagt.




Ah, ein harter. Auf der einen Seite ist eine Deklaration ein Vertrag und es macht keinen Sinn, ein const-Argument als Wert zu übergeben. Auf der anderen Seite, wenn Sie sich die Funktionsimplementierung ansehen, geben Sie dem Compiler mehr Möglichkeiten zur Optimierung, wenn Sie ein Argument als konstant deklarieren.




const ist sinnlos, wenn das Argument per Wert übergeben wird, da Sie das Objekt des Aufrufers nicht ändern werden.

const sollte bei der Referenzübergabe bevorzugt werden, es sei denn, der Zweck der Funktion besteht darin, den übergebenen Wert zu ändern.

Schließlich kann eine Funktion, die das aktuelle Objekt (this) nicht ändert, und sollte wahrscheinlich als const deklariert werden. Ein Beispiel ist unten:

int SomeClass::GetValue() const {return m_internalValue;}

Dies ist ein Versprechen, das Objekt, auf das dieser Aufruf angewendet wird, nicht zu ändern. Mit anderen Worten können Sie anrufen:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

Wenn die Funktion nicht const wäre, würde dies zu einer Compiler-Warnung führen.




Werteparameter 'const' zu kennzeichnen ist definitiv eine subjektive Sache.

Ich bevorzuge es jedoch, Werteparameter wie in Ihrem Beispiel zu markieren.

void func(const int n, const long l) { /* ... */ }

Der Wert für mich zeigt deutlich an, dass die Funktionsparameterwerte niemals durch die Funktion geändert werden. Sie haben am Anfang den gleichen Wert wie am Ende. Für mich ist es Teil einer sehr funktionalen Programmierung Stil.

Für eine kurze Funktion ist es wohl eine Verschwendung von Zeit / Raum, um das 'const' dort zu haben, da es normalerweise ziemlich offensichtlich ist, dass die Argumente nicht durch die Funktion modifiziert werden.

Für eine größere Funktion ist dies jedoch eine Form der Implementierungsdokumentation und wird vom Compiler durchgesetzt.

Ich kann sicher sein, dass ich, wenn ich mit 'n' und 'l' rechne, diese Rechnung umrechnen kann, ohne Angst davor, ein anderes Ergebnis zu bekommen, weil ich einen Ort verpasst habe, an dem einer oder beide geändert werden.

Da es sich um ein Implementierungsdetail handelt, müssen Sie die Werteparameter const nicht im Header deklarieren, genauso wie Sie die Funktionsparameter nicht mit denselben Namen deklarieren müssen, wie die Implementierung es verwendet.




In dem Fall, den Sie erwähnen, hat dies keine Auswirkungen auf die Anrufer Ihrer API. Aus diesem Grund wird sie nicht häufig ausgeführt (und ist im Header nicht erforderlich). Es betrifft nur die Implementierung Ihrer Funktion.

Es ist nicht besonders schlimm, aber die Vorteile sind nicht so toll, wenn man bedenkt, dass es Ihre API nicht beeinflusst, und es fügt Typisierung hinzu, so dass es normalerweise nicht gemacht wird.




Ich benutze nicht const für value-passed parametere. Dem Aufrufer ist es egal, ob Sie den Parameter ändern oder nicht, es ist ein Implementierungsdetail.

Was wirklich wichtig ist, ist, Methoden als const zu markieren, wenn sie ihre Instanz nicht ändern. Machen Sie das so, wie Sie gehen, weil Sie sonst entweder eine Menge const_cast <> haben oder Sie merken, dass das Markieren einer Methode const es erfordert, viel Code zu ändern, weil es andere Methoden aufruft, die als const markiert werden sollten.

Ich neige auch dazu, lokale vars const zu markieren, wenn ich sie nicht ändern muss. Ich glaube, es macht den Code leichter verständlich, indem es die Identifizierung der "beweglichen Teile" erleichtert.




Ich tendiere dazu, const wo immer möglich zu verwenden. (Oder ein anderes geeignetes Schlüsselwort für die Zielsprache.) Ich mache dies nur deswegen, weil es dem Compiler erlaubt, zusätzliche Optimierungen vorzunehmen, die er sonst nicht machen könnte. Da ich keine Ahnung habe, was diese Optimierungen sind, mache ich es immer, auch wenn es albern erscheint.

Nach allem, was ich weiß, kann der Compiler sehr gut einen const-Wert-Parameter sehen und sagen: "Hey, diese Funktion ändert es sowieso nicht, also kann ich durch Verweis übergeben und einige Taktzyklen speichern." Ich denke nicht, dass es jemals so etwas tun würde, da es die Funktionssignatur ändert, aber es macht den Punkt. Vielleicht macht es eine andere Stapelmanipulation oder etwas ... Der Punkt ist, ich weiß es nicht, aber ich weiß, dass es klüger ist, als der Compiler nur dazu führt, dass ich beschämt werde.

C ++ hat etwas zusätzliches Gepäck mit der Idee der Const-Korrektheit, also wird es sogar noch wichtiger.




Ich benutze const, wo ich kann. Const für Parameter bedeutet, dass sie ihren Wert nicht ändern sollten. Dies ist besonders wertvoll, wenn man auf eine Referenz verweist. const for function deklariert, dass die Funktion die Klassenmember nicht ändern soll.




Vielleicht ist dies kein gültiges Argument. Wenn wir jedoch den Wert einer const-Variablen innerhalb eines Funktionscompilers erhöhen, erhalten wir einen Fehler: " error: increment of read-only parameter ". Das bedeutet, dass wir das const-Schlüsselwort verwenden können, um zu verhindern, dass unsere Variablen versehentlich in Funktionen geändert werden (die wir nicht / nur lesen dürfen). Wenn wir also versehentlich zum Kompilierzeitpunkt das gemacht haben, wird uns Compiler dies wissen lassen. Das ist besonders wichtig, wenn Sie nicht der einzige sind, der an diesem Projekt arbeitet.




Der Const-Parameter ist nur nützlich, wenn der Parameter als Referenz übergeben wird, dh entweder als Referenz oder als Zeiger. Wenn der Compiler einen const-Parameter sieht, stellen Sie sicher, dass die im Parameter verwendete Variable nicht im Rumpf der Funktion geändert wird. Warum sollte jemand einen Nebenwertparameter als konstant festlegen? :-)




Wenn der Parameter als Wert übergeben wird (und keine Referenz ist), gibt es normalerweise keinen großen Unterschied, ob der Parameter als const deklariert ist oder nicht (es sei denn, er enthält ein Referenzelement - kein Problem für integrierte Typen). Wenn der Parameter eine Referenz oder ein Zeiger ist, ist es normalerweise besser, den referenzierten / zugewiesenen Speicher zu schützen, nicht den Zeiger selbst (Ich denke, Sie können die Referenz nicht selbst const machen, nicht, dass es wichtig ist, den Schiedsrichter nicht zu ändern) .. Es scheint eine gute Idee zu sein, alles zu schützen, was Sie als const. Sie können es weglassen, ohne Angst haben zu müssen, einen Fehler zu machen, wenn die Parameter nur PODs (einschließlich integrierter Typen) sind und es keine Möglichkeit gibt, dass sie sich entlang der Straße weiter verändern (z. B. in Ihrem Beispiel der bool-Parameter).

Ich wusste nicht über die Unterschiede in der .h / .cpp-Datei, aber es macht Sinn. Auf Maschinencodeebene ist nichts "const". Wenn Sie also eine Funktion (in der .h) als nicht-const deklarieren, ist der Code derselbe, als wenn Sie ihn als const deklarieren (Optimierungen beiseite). Es hilft Ihnen jedoch, den Compiler zu registrieren, dass Sie den Wert der Variable in der Implementierung der Funktion (.ccp) nicht ändern werden. Es kann nützlich sein, wenn Sie von einer Schnittstelle erben, die eine Änderung zulässt, aber Sie müssen nicht zu einem Parameter wechseln, um die erforderliche Funktionalität zu erreichen.







Zusammenfassen:

  • "Normalerweise ist der konstante Vorbeifahrtswert im besten Fall nutzlos und irreführend." Von GOTW006
  • Aber Sie können sie in der CPP wie mit Variablen hinzufügen.
  • Beachten Sie, dass die Standardbibliothek nicht const verwendet. ZB std::vector::at(size_type pos) . Was gut genug für die Standardbibliothek ist, ist gut für mich.



Ich würde nicht konstante Parameter wie diese setzen - jeder weiß bereits, dass ein boolescher Wert (im Gegensatz zu einem booleschen &) konstant ist. Wenn man ihn also hinzufügt, wird man denken, "warte, was?" oder sogar, dass Sie den Parameter als Referenz übergeben.




Die Sache, die man sich mit const merken sollte, ist, dass es viel einfacher ist, die Dinge von Anfang an konstant zu machen, als zu versuchen, sie später einzufügen.

Verwenden Sie const, wenn Sie möchten, dass etwas unverändert bleibt - es ist ein zusätzlicher Hinweis, der beschreibt, was Ihre Funktion macht und was sie erwartet. Ich habe viele C-APIs gesehen, die mit einigen von ihnen funktionieren könnten, besonders solche, die C-Strings akzeptieren!

Ich würde das Schlüsselwort const in der cpp-Datei lieber weglassen als den Header, aber da ich dazu tendiere, sie einzufügen und einzufügen, werden sie an beiden Stellen beibehalten. Ich habe keine Ahnung, warum der Compiler das zulässt, ich denke, es ist ein Compiler. Best Practice ist definitiv, Ihr const Schlüsselwort in beide Akten zu setzen.




Es gibt wirklich keinen Grund, einen Wert-Parameter "const" zu machen, da die Funktion sowieso nur eine Kopie der Variablen verändern kann.

Der Grund für die Verwendung von "const" ist, wenn Sie etwas größeres übergeben (z. B. eine Struktur mit vielen Elementen) als Referenz, in diesem Fall stellt es sicher, dass die Funktion es nicht ändern kann; oder eher, der Compiler wird sich beschweren, wenn Sie versuchen, es in der herkömmlichen Weise zu ändern. Es verhindert, dass sie nicht versehentlich geändert.




Als Parameter Wert übergeben wird, tut es keinen Unterschied machen, wenn Sie const oder nicht von der rufenden Funktion des perspective.It gibt grundsätzlich keinen Sinn machen Pass von Wertparameter als const zu deklarieren.




Alle consts in Ihre Beispiele haben keinen Zweck. C ++ ist Pass-by-Wert standardmäßig, so dass die Funktion bekommt Kopien dieser ints und booleans. Auch wenn die Funktion sie tut ändern, die Kopie des Anrufers ist nicht betroffen.

Also würde ich zusätzliche consts vermeiden, weil

  • Sie sind redudant
  • Sie verunstalteten den Text
  • Sie verhindern, dass mich von dem in den Fällen, in Wert übergeben zu ändern, wo es könnte nützlich oder effizient sein.



Ich weiß, dass die Frage „etwas“ veraltet ist, aber wie ich accross es kam jemand anders auch so in Zukunft kann tun ... ... noch bezweifle ich, der arme Kerl wird hier Liste unten meinen Kommentar zu lesen :)

Es scheint mir, dass wir immer noch zu zu Denk C-Stil Art und Weise beschränkt sind. In dem OOP Paradigma spielen wir mit Objekten um, keine Typen. Const Objekt kann aus einem nicht-const Objekt konzeptionell unterschiedlich sein, und zwar im Sinne einer logischen const (im Gegensatz zur bitweisen-const). Selbst wenn also const Korrektheit der Funktion params ist (vielleicht) ein über Sorgfältigkeit bei PODs ist es nicht so im Fall von Objekten. Wenn eine Funktion mit einem konstanten Objekt arbeitet, soll es so sagen. Betrachten Sie den folgenden Code-Schnipsel

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

ps .: können Sie, dass (const) argumentieren Referenz hier besser geeignet wäre, und gibt Ihnen das gleiche Verhalten. Nun ja, richtig. Nur gibt ein anderes Bild von dem, was ich an anderer Stelle sehen konnte ...




Als VB.NET Programmierer, die ein C ++ Programm mit 50+ exponierten Funktionen und eine .h-Datei verwenden muss, die den const Qualifier sporadisch verwenden, ist es schwierig zu wissen, wann eine Variable für den Zugriff auf ByRef oder ByVal verwenden.

Natürlich ist das Programm sagt Ihnen, durch einen Ausnahmefehler auf der Linie zu erzeugen, wo Sie den Fehler gemacht, aber dann müssen Sie falsch, welche der 2-10 Parameter zu erraten ist.

So, jetzt habe ich die geschmacklos Aufgabe zu versuchen, einen Entwickler zu überzeugen, dass sie wirklich ihre Variablen definieren sollten (in der H-Datei) auf eine Weise, die leicht eine automatisierte Methode zur Erstellung von all den VB.NET Funktionsdefinitionen ermöglicht. Sie werden dann selbstgefällig sagen: „Lesen Sie die ... Dokumentation.“

Ich habe einen awk-Skript geschrieben, das eine .h-Datei analysiert und erstellt alle der Declare Function Befehle, aber ohne einen Indikatoren, welche Variablen R / O vs R / W ist, ist es nur, dass die halbe Arbeit.

BEARBEITEN:

Auf Anregung eines anderen Benutzers ich folgend bin hinzuzufügen;

Hier ist ein Beispiel eines (IMO) schlecht .h Eintrag gebildet;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

Das resultierende VB aus meinem Skript;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

Beachten Sie den fehlenden „const“ auf dem ersten Parameter. Ohne sie ein Programm (oder ein anderer Entwickler) hat keine Ahnung, der erste Parameter soll übergeben werden „ByVal.“ Durch das Hinzufügen des „const“ macht es die .h-Datei selbstdokumentiere, so dass Entwickler andere Sprachen mit leicht funktionierenden Code schreiben können.