avr-gcc C ++コンストラクターに渡された文字列をコピーする必要を防ぐにはどうすればよいですか?
質問
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_;
};
動的メモリ割り当てを廃止できるように、インターフェイスを「正しく」使用するように変更する方法はありますか?
解決
オーバーロードされたコンストラクターを2つ提供するとどうなりますか?
TestSuite(const char* name) ...
TestSuite(char* name) ...
const char*
を指定して呼び出した場合、コンストラクターはポインターのコピーを作成できますが、文字列が消えないことを前提としています。 char*
で呼び出された場合、コンストラクターは文字列全体のコピーを作成できます。
name
が実際に動的に割り当てられているときに、コンストラクターに<=>を渡すことで、このメカニズムを破壊することも可能です。ただし、これは目的には十分かもしれません。
このテクニックがAPIで実際に使用されたことは一度も見たことがないことに注意してください。質問を読んでいるときに思いついたのです。
他のヒント
ドキュメント。たとえば、
/**
* Test suite constructor.
* @param name test suite name cstring, shared
*/
TestSuite(char const *name) {
// ...
共有ポインターは、このオブジェクトの存続期間中、ポイントされたオブジェクトが生きていなければならないことを意味します。
まあ、すべてのメモリ割り当てを処理する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];
};
ただし、これはメモリを浪費するため、組み込みプラットフォームでは問題になる可能性があります。
char name[XYZ]
<!> nbsp; TestSuiteのメンバー(名前を快適に表示するのに十分なXYZを持つ)を用意し、strncpy
を使用して文字列をコピーします(最大長XYZ-1)。 / p>
コンストラクタで文字列リテラルまたはchar *を取ることができる素敵なC ++文字列クラスがあるのに、なぜchar *とmallocを使用するのですか?
std :: stringを使用できますか? std::string name_
として使用し、STLにメモリ割り当てを処理させることができます。
class TestSuite {
public:
TestSuite(const char* name) : name_(name) {}
~TestSuite() {}
private:
std::string name_;
};
<string>
を含めることを忘れないでください。