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

程序中有两个问题

B *vBptr;

您的指针尚未初始化,虽然它是 B 类型的指针,但未指向 B 类型的有效对象。将其更改为

B *vBptr = new B();

vVec.resize(1);

这里调整大小不会为向量的每个元素分配存储空间。您可以通过将初始化提供给向量的 resize 方法来使用实际对象初始化元素

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类违反了三规则(手动管理资源时的默认复制构造函数/赋值操作)。因此,如果您复制一个B对象,将会发生可怕的事情(准确地说是双重释放并访问已删除的内存)。

因此,我建议您使用某种智能指针。如果您使用 c++11,您可以使用std::shared_ptror 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++11std::unique_ptr是您的朋友,否则 iirc boost 具有boost::unique_ptr. 只是远离std::auto_ptr。除非您喜欢增加的复杂性/潜在的错误,或者您的代码对性能非常敏感(并且使用非常高效的自定义分配器),否则几乎没有理由手动管理您的内存。

于 2012-05-01T16:47:13.103 回答
0
B *vBptr;
vBptr->access().print(); //Segmentation fault!

嗯,当然; 您创建了一个变量来存储指向 B 对象的指针,但实际上并没有让它指向 B 对象。(提示:查看您为 B 类编写的代码,其中 BA* mP1指向某事?)

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

嗯,当然; 您创建了一个指向 B 对象的指针向量,然后调整向量的大小以添加一个元素;该元素是默认构造的指向 B 的指针。对于指针类型,默认构造是空指针,因此您也没有指向任何实际的 B 对象。

您的问题与任何 A 或 B 实现无关。

那我怎么能创建一个指向 B 对象的指针向量

为什么你认为你想这样做?只制作 B 对象的向量有什么问题?

于 2012-05-01T16:29:50.610 回答
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 NOT 吗?

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 回答