1

请看一下这段代码:

#include <vector>
#include <iostream>
#include <string>
using namespace std;

class A
{
    private:
        string contentA;

    public:
        A(){ contentA = ""; };
        A( string setContent ){ contentA = setContent; };
        virtual string printContent(){ return contentA; };
};

class B: public A
{
    private:
        string contentB;

    public:
        B( string setContent ){ contentB = setContent; };
        virtual string printContent(){ return contentB; };
};

int main()
{

    vector<A*> aPointer;
    vector<B> bVector;      

    B b1("b1");
    //store b1 obj in bVector
    bVector.push_back( b1 );
    //store the current(last) obj address to aPointer for access later
    aPointer.push_back( &bVector.back() );

//    B b2("b2");
//    bVector.push_back( b2 );
//    aPointer.push_back( &bVector.back() );

    for( vector<A*>::iterator it = aPointer.begin(); it != aPointer.end(); it++ )
    {
        cout << (*it)->printContent() << endl;
    }
}

aPointer 将存储指向 B 向量元素的指针。

请问为什么在for循环中访问B向量中的第二个元素时会出现分段错误?

我已经输入了十六进制,它会再次正常工作。

4

3 回答 3

6

你必须记住 astd::vector的大小是可变的。当您将元素添加到向量时,它可能必须重新分配数据,因此任何指向该向量的指针在重新分配后都将无效。

这里发生的情况可能是这样的重新分配,因此一个指针将无效并且取消引用它将是未定义的行为,并且在您的情况下会导致崩溃。

于 2013-10-24T07:57:43.563 回答
2

问题不在于您访问 的第二个元素时aPointer:它是您访问第一个元素时。正如您将看到的,此问题是在std::vector增长/调整大小和重新分配内存时引起的。当它这样做时,引用(指针、迭代器和&引用)无效,这意味着当您访问这些无效引用时它会导致未定义的行为(在您的情况下,效果是分段错误)。

让我们看看真正导致问题的原因:

B b1("b1");
bVector.push_back( b1 );
aPointer.push_back( &bVector.back() );

B b2("b2");
bVector.push_back( b2 );
aPointer.push_back( &bVector.back() );

哦!您正在推回两个元素,它们的地址在添加时存储。问题就在那里。当您执行第二个push_back时,它会导致重新分配和调整大小,从而使对内部现有元素的引用无效bVector。而且您在该向量中有一个现有元素,并且对它的引用已经无效!该引用当前是第一个元素,aPointer它指向您不应该指向和访问的内存位置。

因此,当您进行迭代时,您会访问 的第一个元素aPointer,从而导致分段错误。

为了解决您的问题,不要存储指向另一个向量的相应元素的指针向量!您可以只传递整个向量(最好通过引用,这样我们就不会产生复制成本)并直接对元素本身进行操作。这肯定会为您节省一个小时的头痛,并会产生更好、更短的代码。

于 2013-10-24T08:03:04.030 回答
1

正如 Joachim Pileborg 和 Mark Garcia 所提到的,这是向量容器重新分配内存的问题。

要解决此问题,您可以使用该vector.reserve方法为向量预分配内存。虽然这适用于您的情况,但这只是一个创可贴,不应被视为解决此问题的方法。编辑:我想强调我发布这个只是因为它可能很有趣。Joachim 和 Mark 提供了解决根本问题的适当方法。

int main()
{

    vector<A*> aPointer;
    vector<B> bVector;      

    //reserve some space. There's no special meaning to choosing 16.
    aPointer.reserve(16);
    bVector.reserve(16); 

    B b1("b1");
    bVector.push_back( b1 );
    aPointer.push_back( &bVector.back() );

    B b2("b2");
    bVector.push_back( b2 );
    aPointer.push_back( &bVector.back() );

    for( vector<A*>::iterator it = aPointer.begin(); it != aPointer.end(); it++ )
    {
        cout << (*it)->printContent() << endl;
    }
}
于 2013-10-24T08:14:12.183 回答