Как я могу предотвратить необходимость копирования строк, переданных в конструктор avr-gcc C ++? - PullRequest
2 голосов
/ 22 июня 2009

В библиотеке модульного тестирования ArduinoUnit я предоставил механизм присвоения имени TestSuite. Пользователь библиотеки может написать следующее:

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

Это ожидаемое использование - имя TestSuite является строковым литералом. Однако, чтобы предотвратить трудно обнаруживаемые ошибки, я чувствую себя обязанным использовать различные способы использования, например:

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

Как таковой, я реализовал TestSuite следующим образом:

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

  ~TestSuite() {
    free(name_);
  }

private:
  char* name_;
};

Оставляя в стороне проблему неудачи при распределении памяти в конструкторе, я бы предпочел просто выделить указатель на переменную-член следующим образом:

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

private:
  const char* name_;
};

Можно ли как-то изменить интерфейс, чтобы заставить его использовать «правильно», чтобы я мог покончить с динамическим распределением памяти?

Ответы [ 6 ]

2 голосов
/ 22 июня 2009

Что если вы предоставите два перегруженных конструктора?

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

Если вызывается с const char*, тогда конструктор может сделать копию указателя, предполагая, что строка не исчезнет. Если вызывается с char*, конструктор может сделать копию всей строки.

Обратите внимание, что все еще возможно подорвать этот механизм, передав const char* в конструктор, когда name фактически выделен динамически. Однако этого может быть достаточно для ваших целей.

Должен заметить, что я никогда не видел, чтобы эта техника использовалась в API, это была мысль, которая пришла мне в голову, когда я читал ваш вопрос.

1 голос
/ 22 июня 2009

Имейте элемент char name[XYZ] вашего TestSuite (с XYZ, достаточно большим, чтобы удобно отображать имя), и используйте strncpy для копирования строки (с максимальной длиной XYZ-1).

1 голос
/ 22 июня 2009

Документация. Например,

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

Общий указатель подразумевает, что указанный объект должен быть живым в течение времени жизни этого объекта.

1 голос
/ 22 июня 2009

Ну, вы можете использовать std :: string, которая позаботится обо всем распределении памяти

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

  ~TestSuite() {
  }

private:
  std::string name_;
};

Редактировать : Если вы хотите избежать вызова malloc (), вы можете сделать это:

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

private:
  char name_[16];
};

Однако это приведет к потере некоторой памяти, что может быть проблемой на встроенных платформах.

0 голосов
/ 22 июня 2009

Вы можете использовать std :: string? Вы можете иметь его как std::string name_ и STL позаботится о выделении памяти для вас ..

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

      ~TestSuite() {}

    private:
      std::string name_;
};

Не забудьте включить <string>.

Ссылка

0 голосов
/ 22 июня 2009

Почему вы используете char * и malloc, когда у вас есть хороший класс C ++ string, который может принимать строковый литерал или char * в своем конструкторе?

...