c++ rückgabewerte - Zwischenspeichern eines Const Char * als Rückgabetyp




6 Answers

Wie wäre es damit:

const char *getHelloString() const
{
    return "HelloWorld!";
}

Die direkte Rückgabe eines Literals bedeutet, dass der Speicherplatz für die Zeichenfolge vom Compiler im statischen Speicher reserviert wird und während der gesamten Dauer des Programms verfügbar ist.

übergeben funktion

Ich habe etwas über C ++ gelesen und diesen Artikel über RTTI (Runtime Type Identification) gefunden: http://msdn.microsoft.com/en-us/library/70ky2y6k(VS.80).aspx . Nun, das ist ein anderes Thema :) - Ich stolperte jedoch über ein seltsames Sprichwort in der type_info Klasse, nämlich über die ::name Methode. Darin heißt es: "Die type_info::name gibt ein const char* an eine mit Null abgeschlossene Zeichenfolge zurück, die den lesbaren Namen des Typs darstellt. Der Speicher, auf den verwiesen wird, wird zwischengespeichert und sollte niemals direkt freigegeben werden."

Wie kannst du so etwas selbst umsetzen? Ich habe mich schon oft mit genau diesem Problem herumgeschlagen, weil ich kein neues char Array für den Aufrufer erstellen möchte, um es zu löschen, also bin ich bis jetzt bei st std::string .

Lassen Sie uns der Einfachheit halber sagen, dass ich eine Methode erstellen möchte, die "Hello World!" nennen wir es

const char *getHelloString() const;

Persönlich würde ich es irgendwie so machen (Pseudo):

const char *getHelloString() const
{
  char *returnVal = new char[13];
  strcpy("HelloWorld!", returnVal);

  return returnVal
}

.. Aber das würde bedeuten, dass der Aufrufer eine delete[] auf meinem Rückkehrzeiger machen sollte :(

Danke im Voraus




Nun gut, wenn wir nur über eine Funktion sprechen, die Sie immer den gleichen Wert zurückgeben möchten. Es ist ganz einfach.

const char * foo() 
{
   static char[] return_val= "HelloWorld!";
   return return_val;
}

Das Schwierige ist, wenn Sie anfangen, Dinge zu tun, wo Sie das Ergebnis zwischenspeichern, und dann müssen Sie Threading in Betracht ziehen, oder wenn Ihr Cache ungültig wird, und versuchen, etwas im lokalen Thread-Speicher zu speichern. Aber wenn es nur eine einmalige Ausgabe ist, die sofort kopiert wird, sollte dies den Trick machen.
Alternativ, wenn Sie keine feste Größe haben, müssen Sie etwas tun, wo Sie entweder einen statischen Puffer beliebiger Größe verwenden müssen .. in dem Sie möglicherweise etwas zu groß haben, oder wenden Sie sich an eine verwaltete Klasse say std::string .

const char * foo() 
{
   static std::string output;
   DoCalculation(output);
   return output.c_str();
}

auch die Funktionssignatur

const char *getHelloString() const;

gilt nur für Mitgliedsfunktionen. An diesem Punkt müssen Sie sich nicht mit den lokalen Variablen der statischen Funktion befassen und könnten nur eine Elementvariable verwenden.




Seien Sie vorsichtig beim Implementieren einer Funktion, die einen Teil des Speichers zuweist und erwartet dann, dass der Aufrufer die Zuweisung aufhebt, wie Sie es im OP tun:

const char *getHelloString() const
{
  char *returnVal = new char[13];
  strcpy("HelloWorld!", returnVal);

  return returnVal
}

Dadurch übertragen Sie den Besitz des Speichers an den Aufrufer. Wenn Sie diesen Code von einer anderen Funktion aufrufen:

int main()
{
  char * str = getHelloString();
  delete str;
  return 0;
}

... die Semantik der Übertragung des Eigentums an dem Speicher ist nicht klar, was zu einer Situation führt, in der Fehler und Speicherlecks wahrscheinlicher sind.

Wenn sich die beiden Funktionen in zwei verschiedenen Modulen befinden, können Sie den Heap möglicherweise beschädigen, zumindest unter Windows. Insbesondere, wenn main () in hallo.exe ist, in VC9 kompiliert ist und sich getHelloString () in der Datei utility.dll befindet, die in VC6 kompiliert wurde, wird der Heap beschädigt, wenn Sie den Speicher löschen. Dies liegt daran, dass VC6 und VC9 beide ihren eigenen Heap verwenden und sie nicht derselbe Heap sind. Sie ordnen also von einem Heap zu und heben die Zuweisung von einem anderen Heap auf.




Was ich oft getan habe, wenn ich diese Art von Funktionalität brauche, ist, einen char * -Zeiger in der Klasse zu haben - initialisiert auf null - und bei Bedarf zuzuweisen.

nämlich:

class CacheNameString
{
    private: 
        char *name;
    public:
        CacheNameString():name(NULL)  { }

    const char *make_name(const char *v)
    {
        if (name != NULL)
            free(name);

        name = strdup(v);

        return name;
    }

};



Der Ratschlag, der vor der Lebensdauer der zurückgegebenen Saite warnt, ist eine akustische Empfehlung. Sie sollten immer vorsichtig sein, Ihre Verantwortlichkeiten zu erkennen, wenn es darum geht, die Lebensdauer von zurückgegebenen Zeigern zu verwalten. Die Praxis ist jedoch ziemlich sicher, vorausgesetzt, die Variable, auf die gezeigt wird, überlebt den Aufruf der Funktion, die sie zurückgegeben hat. Betrachten wir zum Beispiel den Zeiger auf const char, der von c_str() als Methode der Klasse std::string . Dies gibt einen Zeiger auf den Speicher zurück, der von dem Zeichenfolgenobjekt verwaltet wird, das garantiert gültig ist, solange das Zeichenfolgenobjekt nicht gelöscht oder sein interner Speicher neu zugewiesen wird.

Im Falle der Klasse std::type_info ist es ein Teil des C ++ - Standards, wie sein Namensraum andeutet. Der von name() Speicher wird auf den statischen Speicher verwiesen, der vom Compiler und Linker beim Kompilieren der Klasse erstellt wurde und Teil des RTTI-Systems (Run Time Type Identification) ist. Da es sich auf ein Symbol im Coderaum bezieht, sollten Sie nicht versuchen, es zu löschen.




Es ist wahrscheinlich mit einem statischen Puffer gemacht:

const char* GetHelloString()
{
    static char buffer[256] = { 0 };
    strcpy( buffer, "Hello World!" );
    return buffer;
}

Dieser Puffer ist wie eine globale Variable, auf die nur von dieser Funktion aus zugegriffen werden kann.




Related

c++ char return-value