1

クラス A に何らかのデータを含め、クラス B にそのデータへのポインタを含めたいと考えています。データ オブジェクト A への参照を返す関数を介してデータへのアクセスを提供しています。オブジェクト B を作成すると、オブジェクト A にアクセスできますが、B へのポインターを作成すると、同等の操作でセグメンテーション エラーが発生します。このような:

#include <iostream>
#include <vector>

class A {
public:
    A(const int pInt) {mInt = pInt;}
    void print() {std::cout << mInt << std::endl;}
private:
    int mInt; //some data
};

class B {
public:
   B() {mP1 = new A(1);} //initialise to 1
   ~B() {delete mP1;}
   A& access() {return *mP1;} //return reference to the data

private:
    A* mP1; //pointer to some data
};

int main() {
    B vB;
    vB.access().print(); //this works.

    B *vBptr;
    vBptr->access().print(); //Segmentation fault!

    std::vector<B*> vVec;
    vVec.resize(1);
    vVec[0]->access().print(); //Segmentation fault!
}

B *vBptr を作成するときに、B オブジェクトが初期化されていないと思いますか? では、自動的に初期化される B オブジェクトへのポインタのベクトルを作成するにはどうすればよいでしょうか?

乾杯。

4

7 に答える 7

3

ポインターを初期化する必要があります。

B *vBptr = new B;
vBptr->access().print();

ベクターにも同じことが当てはまります - 要素を繰り返し処理して初期化する必要があります。

for ( int i = 0 ; i < vVec.size() ; i++ )
   vVec[i] = new B;

メモリを手動で解放する必要があることに注意してください

delete vBptr;

for ( int i = 0 ; i < vVec.size() ; i++ )
   delete vVec[i];

メモリ リークが発生しないようにします。

于 2012-05-01T16:27:24.053 に答える
2

プログラムの 2 つの問題

B *vBptr;

ポインターは初期化されておらず、タイプ B のポインターですが、タイプ B の有効なオブジェクトを指していません。

B *vBptr = new B();

vVec.resize(1);

ここで、サイズ変更は、ベクトルの各要素にストレージを割り当てません。ベクトルのサイズ変更メソッドに初期化を指定することで、実際のオブジェクトで要素を初期化できます。

vVec.resize(1,new B());
于 2012-05-01T16:35:39.593 に答える
1

実際には、ポインターを何かに設定する必要があります。

B *vBptr;          // bad -- uninitialized 
B *vBptr = new B;  // proper
于 2012-05-01T16:27:59.477 に答える
1

他の回答で述べたように、ポインター変数は自動的にメモリを割り当てないため、次のようにメモリを手動で割り当ておよび割り当て解除する必要があります。

B vB;
vB.access().print(); //this works.

B *vBptr = new B;//allocate memory for vBptr
vBptr->access().print();
delete vBptr;//clean up of vBptr
std::vector<B*> vVec;
vVec.push_back(new B);
vVec[0]->access().print(); 
delete vVec[0];

ただし、メモリリークやエラーが発生しやすいため、生のポインタでメモリを管理しないことをお勧めします。vBptr->access().print()たとえば、上記のコードで例外がスローされると、メモリ リークが発生します。あなたのBクラスは 3 つのルールに違反しています (手動でリソースを管理している間のデフォルトのコピー コンストラクター/代入操作)。したがって、Bオブジェクトをコピーすると、恐ろしいことが起こります (正確には、二重解放と、既に削除されたメモリへのアクセス)。

したがって、ある種のスマートポインターを使用することをお勧めします。C++11 を使用する場合はstd::shared_ptrまたはを使用できます。std::unique_ptrそれ以外の場合は ですstd::tr1::shared_ptr。コンパイラに tr1 がない場合、boost にもありますboost:shared_ptr。次に、コードは次のようになります。

class B {
public:
   B():mP1(new A(1)) {} //initialise to 1
   ~B() {} //no extra managing necessary
   A& access() {return *mP1;} //return reference to the data

private:
    std::shared_ptr<A> mP1; //pointer to some data
};

int main() {
    B vB;
    vB.access().print(); //this works.

    std::shared_ptr<B> vBptr(new B);
    vBptr->access().print();

    std::vector<std::shared_ptr<B> > vVec;
    vVec.push_back(std::shared_ptr<B>(new B));
    vVec[0]->access().print(); 
}

オーバーヘッドを最小限に抑える必要があり、c++ 11 を使用しているstd::unique_ptr場合は友人boost::unique_ptrです。から離れてstd::auto_ptrください。追加の複雑さ/バグの可能性が気に入らない場合、またはコードが非常にパフォーマンスに敏感な場合 (および非常に効率的なカスタム アロケーターを使用する場合) を除き、メモリを手動で管理する理由はほとんどありません。

于 2012-05-01T16:47:13.103 に答える
0
B vB;
vB.access().print();

B *vBptr = &vB; // or B *vBptr = new B;
vBptr->access().print();

std::vector<B*> vVec;
vVec.push_back(&vB);  // vVec.push_back(new B);
vVec[0]->access().print(); 

しかし、このようにではなく、Bを書く必要がありますか?

class B {
 public:
  //   B() {}
  //   ~B() {}
  A& access() {return a;}

private:
   A a;};
于 2012-05-01T16:33:01.837 に答える
0

貢献してくれたすべての人に感謝します。以下は、私が採用した実装、つまりboost::shared_ptrを使用したものです:

#include <iostream>
#include <vector>
#include "boost/smart_ptr.hpp"

class A {
public:
    A(const int pInt) {mInt = pInt;}
    void print() const {std::cout << mInt << std::endl;}
    void set(const int pInt) {mInt = pInt;}
private:
    int mInt; //some data
};

class B {
public:
    B() {}  //leave A pointer as null
    ~B() { } //delete handled by shared_ptr
    A& access() {return *mP1;} //return reference to the data
    boost::shared_ptr<A>& access_A_ptr() {return mP1;} //return the pointer for assignment

private:
    boost::shared_ptr<A> mP1;
};

int main() {

    std::vector< boost::shared_ptr<A> > vVecA; //data to be shared
    for (unsigned int i = 0; i < 5; i++) {
        boost::shared_ptr<A> vAptr(new A(i));
        vVecA.push_back(vAptr);
        vVecA[i]->print();
    }

    vVecA[2]->set(123);

    for (unsigned int i = 0; i < vVecA.size(); i++) {
        vVecA[i]->print(); //changes to the underlying objects are reflected
    }

    boost::shared_ptr<B> vBptr(new B); //make an empty B
    vBptr->access_A_ptr() = vVecA[2]; //assignment of shared pointer

    vBptr->access().print();

    std::cout << "use count of vVecA[1] = " << vVecA[1].use_count() << std::endl; // = 1
    std::cout << "use count of vVecA[2] = " << vVecA[2].use_count() << std::endl; // = 2

    std::vector< boost::shared_ptr<B> > vVecB;

    //vVecB.resize(vVecA.size(), boost::shared_ptr<B> (new B) ); //resize and init to a SINGLE B object, NO!!!

    for (unsigned int i = 0; i < vVecA.size(); i++) {
        vVecB.push_back(boost::shared_ptr<B> (new B)); //filling array with separate empty Bs
        vVecB[i]->access_A_ptr() = vVecA[i];
        vVecB[i]->access().print(); // = 0,1,123,3,4
    }

    vVecA[2]->set(2); //changes to A objects reflected in the B objects

    for (unsigned int i = 0; i < vVecB.size(); i++) {
        vVecB[i]->access().print(); // = 0,1,2,3,4
    }

    std::cout << "use count of vVecA[1] = " << vVecA[1].use_count() << std::endl; // = 2
    std::cout << "use count of vVecA[2] = " << vVecA[2].use_count() << std::endl; // = 3

}

これは事実上、共有ポインターの演習になりました。ただし、コメントはあらゆる面で大歓迎です。

ありがとうございました!

于 2012-05-02T09:19:46.467 に答える
0
B *vBptr;
vBptr->access().print(); //Segmentation fault!

もちろんです。B オブジェクトへのポインターを格納する変数を作成しましたが、実際には B オブジェクトを指すようにしませんでした。(ヒント: あなたが B クラスのために書いたコードを参照してください。ここで、B がA* mP1何かを指摘していますか?)

std::vector<B*> vVec;
vVec.resize(1);
vVec[0]->access().print(); //Segmentation fault!

もちろんです。B オブジェクトへのポインターのベクターを作成し、ベクターのサイズを変更して 1 つの要素を追加しました。その要素は、デフォルトで構築された B へのポインターです。ポインター型の場合、デフォルトの構造は null ポインターであるため、実際の B オブジェクトを指しているわけではありません。

あなたの問題は、AまたはBの実装とは何の関係もありません。

Bオブジェクトへのポインターのベクトルを作成するにはどうすればよいですか

なぜこれをやりたいと思うのですか?B オブジェクトのベクトルを作成するだけでは何が問題なのですか?

于 2012-05-01T16:29:50.610 に答える