1

両方の行で同じになるはずです..何が起こるか、2つの異なる値が得られます..異なる位置を目指していたようです..エラーは内部にあると思いますd->add(*b)

出力は

  thiago 14333804
  Ph¿├┌ 2816532

それをよりよく説明するために、以下のコードを置きます

私はプログラムを手に入れました

int main(int argc, char **argv) {

    CClass* c = new CClass();

    BClass* b = c->getNext();

    printf("%s %d \n", b->getValue(), b->getValue());

    DClass* d = new DClass();
    d->add(*b);

    printf("%s %d \n", d->getNext(), d->getNext());

    cin.get();

    return 0;
}

インターフェイスは以下のとおりです

class BClass
{
private:
    char* value;
    bool stale;
public:
    BClass(char* value);
    ~BClass(void);
    char* getValue();
    bool isStale();
};


class CClass
{
private:
    vector<BClass*> list;
public:
    CClass(void);
    ~CClass(void);

    BClass* getNext();
};


class DClass
{
private:
    vector<BClass*> list;
    static bool isStale(BClass* b) { return b->isStale();};
public:
    DClass(void);
    ~DClass(void);
    void add(BClass s);
    char* getNext();
};

そして実装は次のとおりです

//BClass

BClass::BClass(char* value)
{
    this->value = value;
    this->stale = false;
}

BClass::~BClass(void)
{
}

char* BClass::getValue()
{
    return value;
}

bool BClass::isStale()
{
    return stale;
}



//CClass

CClass::CClass(void)
{
    list.push_back(new BClass("thiago"));
    list.push_back(new BClass("bruno"));
    list.push_back(new BClass("carlos"));
}


CClass::~CClass(void)
{
}

BClass* CClass::getNext()
{
    return list.at(0);
}

//DClass

DClass::DClass(void)
{
}

DClass::~DClass(void)
{
}

void DClass::add( BClass s )
{
    list.push_back(&s);
}

char* DClass::getNext()
{
    BClass* b = list.at(0);

    return b->getValue();
}
4

2 に答える 2

5

クラスのインスタンスをB関数D::add()に渡すと、オブジェクトのディープ コピーが作成され、そのコピーがスタックに置かれます。後で、そのコピーのアドレスを使用してリストにプッシュします。関数が完了すると、この自動変数は範囲外になるため、リストに入れていたポインターは無効になります。

修正するには、インターフェースを次のように変更してディープ コピーを回避します。

void DClass::add( BClass * s )
{
    list.push_back(s);
}

あなたのコードが何をしているかのステップバイステップ

  1. BClass* b = c->getNext();// リスト (コンストラクターで作成) から最初の要素のアドレスを取得し、それをb
  2. d->add(*b);// *b は が指すオブジェクトを逆参照bし、呼び出しの準備としてスタックに置きますadd()
  3. void DClass::add( BClass s ){// 逆参照されたオブジェクトのディープ コピーは、この関数のスタック フレームに配置されます
  4. list.push_back(&s);//元のオブジェクトの一時コピーのアドレスを使用して、リストに追加します
  5. }// ここで楽しいことが起こります - 関数が完了すると、スタックが巻き戻され、一時コピーによって以前占有されていたメモリが他の目的に再利用されます。あなたの場合-パラメーターを関数に渡しd->getNext()(非静的メンバー関数には常に非表示のthisパラメーターがあります)、後で関数に渡すために使用されprintf()ます。覚えておいてください-その一時コピーへの以前のポインターはまだスタックを指していますが、現在は別のデータで占有されているため、破損が発生しています

一般的な経験則 - 一時オブジェクトへのポインターを使用しないでください ;-)

于 2012-12-11T19:56:44.767 に答える
1

DClass::add関数ではBClass s、ローカル変数です。

void DClass::add( BClass s )
{
    list.push_back(&s);
}

を呼び出すときは、値d->add(*b);を渡しますBClass。つまり、そのコピーを作成していて、そのコピーのアドレスは元のアドレスと同じではありません。

s関数が戻るとすぐに範囲外になり、それへのポインターは無効になります。したがって、そのポインターを逆参照すると未定義の動作になるため、そのポインターを保存することは役に立ちません。

于 2012-12-11T20:00:34.950 に答える