¿Cómo se puede prevenir la necesidad de copiar cadenas de pasar a un avr-gcc C++ constructor?

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

Pregunta

En el ArduinoUnit unidad de pruebas de la biblioteca me han proporcionado un mecanismo para dar un TestSuite un nombre.Un usuario de la biblioteca puede escribir la siguiente:

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

Este es el uso esperado - el nombre de la TestSuite es un literal de cadena.Sin embargo, para evitar difícil de encontrar bugs me siento obligado a atender para diferentes usos, por ejemplo:

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

Como tal, he implementado TestSuite como este:

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

  ~TestSuite() {
    free(name_);
  }

private:
  char* name_;
};

Dejando de lado el problema de no hacer frente a los errores de asignación de memoria en el constructor prefiero simplemente asignar el puntero a una variable de miembro como este:

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

private:
  const char* name_;
};

Hay alguna manera de que pueda cambiar la interfaz a la fuerza para ser utilizado "correctamente" para que yo pueda acabar con la asignación dinámica de memoria?

¿Fue útil?

Solución

¿Qué sucede si proporciona dos constructores sobrecargados?

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

Si se llama con un const char*, el constructor podría hacer una copia del puntero, suponiendo que la cadena no desaparecerá. Si se llama con un char*, el constructor podría hacer una copia de toda la cadena.

Tenga en cuenta que todavía es posible subvertir este mecanismo pasando un name al constructor cuando el <=> se asigna dinámicamente. Sin embargo, esto puede ser suficiente para sus propósitos.

Debo señalar que nunca he visto esta técnica utilizada en una API, fue solo un pensamiento que se me ocurrió cuando estaba leyendo su pregunta.

Otros consejos

Documentación. Por ejemplo,

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

Un puntero compartido implica que el objeto puntiagudo debe estar vivo durante la vida útil de este objeto.

Bueno, puede usar una cadena std :: que se encargará de toda la asignación de memoria

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

  ~TestSuite() {
  }

private:
  std::string name_;
};

Editar : Si es la llamada a malloc () lo que desea evitar, puede hacer esto:

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

private:
  char name_[16];
};

Sin embargo, esto desperdiciará algo de memoria, lo que puede ser un problema en las plataformas integradas.

Tenga un char name[XYZ] & nbsp; miembro de su TestSuite (con un XYZ lo suficientemente grande como para mostrar cómodamente el nombre) y use strncpy para copiar la cadena (con una longitud máxima de XYZ-1).

¿Por qué estás usando char * y malloc cuando tienes la bonita clase de cadena C ++ que puede tomar un literal de cadena o un char * en su constructor?

Son capaces de usar std::string?Usted podría tener como std::string name_ y tienen la STL cuidar de la asignación de memoria para usted..

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

      ~TestSuite() {}

    private:
      std::string name_;
};

No olvides incluir <string>.

Referencia

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top