Wie kann ich verhindern, dass die Notwendigkeit, Strings zu einem avr-gcc C ++ Konstruktor übergeben zu kopieren?

StackOverflow https://stackoverflow.com/questions/1027416

Frage

In der ArduinoUnit Unit-Tests Bibliothek ich einen Mechanismus zur Verfügung gestellt haben eine Testsuite einen Namen geben . Ein Benutzer der Bibliothek kann schreiben wie folgt vor:

TestSuite suite("my test suite");
// ...
suite.run(); // Suite name is used here

Das ist die erwartete Nutzung - der Name der Testsuite ist ein String-Literal. Jedoch zu verhindern schwer zu finden Bugs, die ich fühle mich verpflichtet, für verschiedene Nutzungen gerecht zu werden, zum Beispiel:

char* name = (char*) malloc(14);
strcpy(name, "my test suite");
TestSuite suite(name);
free(name);
// ...
suite.run(); // Suite name is used here

Als solche habe ich umgesetzt Testsuite wie folgt aus:

class TestSuite {
public:
  TestSuite(const char* name) {
    name_ = (char*) malloc(strlen(name) + 1);
    strcpy(name_, name);
  }

  ~TestSuite() {
    free(name_);
  }

private:
  char* name_;
};

Abgesehen von der Frage der Nichteinhaltung Speicherzuordnungsfehler in dem Konstruktor behandeln ich lieber den Zeiger auf eine Membervariable wie diese einfach zuordnen:

class TestSuite {
public:
  TestSuite(const char* name) : name_(name) {
  }

private:
  const char* name_;
};

Gibt es eine Möglichkeit, die Schnittstelle ändern kann es zu zwingen verwendet ‚richtig‘ werden, so dass ich mit der dynamischen Speicherzuordnung abschaffen kann?

War es hilfreich?

Lösung

Was ist, wenn Sie bieten zwei überladene Konstruktoren?

TestSuite(const char* name) ...
TestSuite(char* name) ...

Wenn mit einem const char* genannt, dann könnte der Konstruktor eine Kopie des Zeigers machen, unter der Annahme, dass die Zeichenfolge nicht weggeht. Wenn mit einem char* genannt wird, könnte der Konstruktor eine Kopie des gesamten String machen.

Beachten Sie, dass es noch möglich ist, diesen Mechanismus zu unterlaufen, indem ein const char* an den Konstruktor übergeben, wenn die name in der Tat ist dynamisch zugewiesen. Dies kann jedoch für Ihre Zwecke ausreichend sein.

Ich sollte anmerken, dass ich nie wirklich diese Technik in einer API verwendet gesehen, es war nur ein Gedanke, der mir einfiel, als ich Ihre Frage war zu lesen.

Andere Tipps

Dokumentation. Zum Beispiel:

/**
* Test suite constructor.
* @param name test suite name cstring, shared
*/
TestSuite(char const *name) {
// ...

Ein gemeinsamer Zeiger bedeutet, dass der spitze Gegenstand während der Laufzeit dieses Objekts am Leben sein muss.

Nun können Sie eine std :: string verwenden, die Pflege aller Speicherzuweisung nehmen

class TestSuite {
public:
  TestSuite(const std::string &name):name_(name) {
  }

  ~TestSuite() {
  }

private:
  std::string name_;
};

Bearbeiten : Wenn es der Aufruf von malloc (), die Sie vermeiden möchten, können Sie dies tun:

class TestSuite {
public:
  TestSuite(const char *name){
    memcpy(name_, name, min(16, strlen(name));
  }

private:
  char name_[16];
};

Dies wird einige Speicher jedoch Abfälle, die auf Embedded-Plattformen ein Problem sein kann.

Haben Sie ein char name[XYZ] Mitglied Ihrer Testsuite (mit einem XYZ groß genug, um bequem den Namen anzuzeigen) und verwenden strncpy die Zeichenfolge zu kopieren (mit einer maximalen Länge von XYZ-1).

Warum verwenden Sie char * und malloc, wenn Sie die schöne C ++ String-Klasse haben, die kann eine Stringliteral oder ein char * in seinem Konstruktor?

Sind Sie in der Lage std :: string zu benutzen? Man könnte es als std::string name_ haben und die STL kümmern sich um die Speicherzuweisung haben für Sie ..

class TestSuite {
    public:
      TestSuite(const char* name) : name_(name) {}

      ~TestSuite() {}

    private:
      std::string name_;
};

Vergessen Sie nicht, <string> aufzunehmen.

Referenz

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