4

最近、C++ コードで非常に奇妙な問題が発生しました。最小限の例でケースを再現しました。Egg クラスがあります。

class Egg
{
private:
    const char* name;
public:
    Egg() {};
    Egg(const char* name) {
        this->name=name;
    }
    const char* getName() {
        return name;
    }
};

卵を保持する Basket クラスもあります

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 Egg4 Egg4 Egg4」が得られます。最後に追加された Egg を動的 Egg 配列のすべてのインデックスに保存します。

Googleで検索した後、Eggのchar * name変数に固定サイズをstrcpy指定し、コンストラクターで使用すると問題が解決することがわかりました。

これが「固定」卵クラスです。

class Egg
{
private:
     char name[50];
public:
    Egg(){};
    Egg(const char* name)
    {
        strcpy(this->name, name);
    }
    const char* getName()
    {
        return name;
    }
};

今、問題はなぜですか?

前もって感謝します。

ここにコード全体へのリンクがあります。

4

4 に答える 4

2

最初のケースでは、文字列を指すポインターをコピーします。

2 番目のケースではstrcpy()、実際に文字列をディープ コピーします。


OK、私は冗長ではありませんでした。明確にさせてください。最初のケースでは、 で作成された文字列を指すポインターをコピーしますostringstream。それが範囲外になるとどうなりますか?

未定義の動作です!

于 2016-04-20T09:18:18.433 に答える
0

コンストラクターで文字列をコピーするのではなく、文字列Eggの開始アドレスであるポインターだけをコピーします。

ostring のすべてのインスタンスが同じ場所にバッファを何度も割り当てるということが起こりました。forそして、たまたま、構築ループと出力印刷ループの間でバッファが上書きされませんでしたfor

そのため、最終的にすべてのEggnameポインターが同じ場所を指し、その場所には構築された姓が含まれます。

于 2016-04-20T09:41:06.230 に答える