Come posso evitare la necessità di copiare le stringhe passate a un costruttore C ++ avr-gcc?

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

Domanda

Nella ArduinoUnit ho fornito un meccanismo per dare un nome a TestSuite . Un utente della libreria può scrivere quanto segue:

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

Questo è l'uso previsto: il nome di TestSuite è letterale stringa. Tuttavia, per prevenire bug difficili da trovare, mi sento obbligato a soddisfare usi diversi, ad esempio:

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

Come tale ho implementato TestSuite in questo modo:

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

  ~TestSuite() {
    free(name_);
  }

private:
  char* name_;
};

Mettendo da parte il problema di non riuscire a gestire gli errori di allocazione della memoria nel costruttore, preferirei semplicemente assegnare il puntatore a una variabile membro come questa:

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

private:
  const char* name_;
};

Esiste un modo per cambiare l'interfaccia per costringerla ad essere utilizzata "correttamente" in modo da poter eliminare l'allocazione dinamica della memoria?

È stato utile?

Soluzione

Cosa succede se si forniscono due costruttori sovraccarichi?

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

Se chiamato con un const char*, il costruttore potrebbe creare una copia del puntatore, supponendo che la stringa non scompaia. Se chiamato con un char*, il costruttore potrebbe creare una copia dell'intera stringa.

Si noti che è ancora possibile sovvertire questo meccanismo passando un name al costruttore quando <=> è effettivamente allocato dinamicamente. Tuttavia, questo potrebbe essere sufficiente per i tuoi scopi.

Dovrei notare che non ho mai visto questa tecnica utilizzata in un'API, è stato solo un pensiero che mi è venuto in mente mentre leggevo la tua domanda.

Altri suggerimenti

Documentazione. Ad esempio,

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

Un puntatore condiviso implica che l'oggetto appuntito deve essere attivo durante la vita di questo oggetto.

Bene, puoi usare una stringa std :: che si occuperà di tutta l'allocazione della memoria

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

  ~TestSuite() {
  }

private:
  std::string name_;
};

Modifica : Se è la chiamata a malloc () che vuoi evitare, puoi farlo:

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

private:
  char name_[16];
};

Ciò sprecherà tuttavia un po 'di memoria, il che può essere un problema su piattaforme integrate.

Avere un char name[XYZ] & nbsp; membro di TestSuite (con una XYZ abbastanza grande da visualizzare comodamente il nome) e usare strncpy per copiare la stringa (con una lunghezza massima di XYZ-1).

Perché stai usando char * e malloc quando hai la bella classe di stringhe C ++ che può prendere una stringa letterale o un char * nel suo costruttore?

Sei in grado di usare std :: string? Potresti averlo come std::string name_ e far sì che l'STL si occupi dell'allocazione di memoria per te ..

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

      ~TestSuite() {}

    private:
      std::string name_;
};

Non dimenticare di includere <string>.

Riferimento

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top