最近、C ++コードで非常に奇妙な問題が発生しました。ミニマリストの例でケースを再現しました。Eggクラスがあります:
class Egg
{
private:
const char* name;
public:
Egg() {};
Egg(const char* name) {
this->name=name;
}
const char* getName() {
return name;
}
};
卵を入れるバスケットクラスもあります
const int size = 15;
class Basket
{
private:
int currentSize=0;
Egg* eggs;
public:
Basket(){
eggs=new Egg[size];
}
void addEgg(Egg e){
eggs[currentSize]=e;
currentSize++;
}
void printEggs(){
for(int i=0; i<currentSize; i++)
{
cout<<eggs[i].getName()<<endl;
}
}
~Basket(){
delete[] eggs;
}
};
したがって、これは期待どおりに機能する例です。
Basket basket;
Egg egg1("Egg1");
Egg egg2("Egg2");
basket.addEgg(egg1);
basket.addEgg(egg2);
basket.printEggs();
//Output: Egg1 Egg2
これは期待どおりの結果ですが、ループ変数に応じて生成された名前でN個の卵を追加したい場合、次の問題が発生します。
Basket basket;
for(int i = 0; i<2; i++) {
ostringstream os;
os<<"Egg"<<i;
Egg egg(os.str().c_str());
basket.addEgg(egg);
}
basket.printEggs();
//Output: Egg1 Egg1
ループ条件をi <5に変更すると、「Egg4 Egg4 Egg4Egg4Egg4」が表示されます。最後に追加されたEggを動的Egg配列のすべてのインデックスに保存します。
グーグルで検索したところ、Eggのchar * name変数に固定サイズを指定strcpy
し、コンストラクターで使用すると問題が解決することがわかりました。
これが「固定」のEggクラスです。
class Egg
{
private:
char name[50];
public:
Egg(){};
Egg(const char* name)
{
strcpy(this->name, name);
}
const char* getName()
{
return name;
}
};
さて、問題はなぜですか?
前もって感謝します。
ここでは、全体のコードへのリンクです。
この式を詳しく見てみましょうos.str().c_str()
。
この関数str
は値ごとに文字列を返します。このように使用すると、返された文字列は、式の終わりまでしか存続しない一時オブジェクトになります。式が終了すると、文字列オブジェクトは破棄され、存在しなくなります。
コンストラクターに渡すポインターは、一時文字列オブジェクトの内部文字列へのポインターです。文字列オブジェクトが破棄されると、そのポインタは無効になり、それを使用すると未定義の動作が発生します。
もちろん、単純な解決策はstd::string
、文字列を使用するときはいつでも使用することです。より複雑な解決策は、配列を使用して、文字列が消える前に文字列の内容をコピーすることです(「fixed」Egg
クラスの場合と同様)。ただし、固定サイズの配列を使用する「固定」ソリューションでは、バッファオーバーフローが発生しやすいことに注意してください。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加