Como posso evitar a necessidade de copiar cordas passados ??para um construtor C avr-gcc ++?

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

Pergunta

Na ArduinoUnit biblioteca de teste de unidade que eu forneci um mecanismo para dar um TestSuite um nome . Um usuário da biblioteca pode escrever o seguinte:

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

Este é o uso esperado - o nome do TestSuite é um literal string. No entanto, para evitar erros difíceis de encontrar Eu me sinto obrigado a atender a diferentes usos, por exemplo:

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

Como tal, eu implementaram TestSuite como esta:

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

  ~TestSuite() {
    free(name_);
  }

private:
  char* name_;
};

Pondo de lado a questão de não lidar com falhas de alocação de memória no construtor eu prefiro simplesmente alocar o ponteiro para uma variável de membro como este:

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

private:
  const char* name_;
};

Existe alguma maneira eu posso mudar a interface para forçá-lo a ser usado 'corretamente' para que eu possa acabar com a alocação dinâmica de memória?

Foi útil?

Solução

E se você fornecer dois construtores sobrecarregados?

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

Se chamado com um const char*, em seguida, o construtor pode fazer uma cópia do ponteiro, assumindo que a cadeia não vai embora. Se chamado com um char*, o construtor pode fazer uma cópia de toda a string.

Note que ainda é possível subverter este mecanismo, passando um const char* para o construtor quando o name é de fato alocada dinamicamente. No entanto, isso pode ser suficiente para seus propósitos.

Devo observar que eu nunca realmente visto esta técnica usada em uma API, que era apenas um pensamento que me ocorreu quando eu estava lendo sua pergunta.

Outras dicas

Documentação. Por exemplo,

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

A compartilhada ponteiro implica que o objeto pontiagudo deve estar vivo durante o tempo de vida deste objeto.

Bem, você pode usar um std :: string que vai cuidar de toda a alocação de memória

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

  ~TestSuite() {
  }

private:
  std::string name_;
};

Editar : Se é a chamada para malloc () que você quer evitar que você poderia fazer isso:

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

private:
  char name_[16];
};

Este vai perder alguma memória no entanto, que pode ser um problema em plataformas embarcadas.

Tenha um membro char name[XYZ] do seu TestSuite (com um grande o suficiente para acomodar confortavelmente XYZ exibir o nome) e uso strncpy para copiar a string (com um comprimento máximo de XYZ-1).

Por que você está usando char * e malloc quando você tem o bom C ++ classe string que pode leva um literal string ou um char * em seu construtor?

Você é capaz de usar std :: string? Você poderia tê-lo como std::string name_ e ter a STL cuidar da alocação de memória para você ..

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

      ~TestSuite() {}

    private:
      std::string name_;
};

Não se esqueça de incluir <string>.

Referência

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top