请看一下这段代码:
#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矢量中的第二个元素时会出现分段错误?
我已经进入了,它会再次正常工作。
答案 0 :(得分:6)
您必须记住std::vector
的大小可变。向向量添加元素时,可能必须重新分配数据,因此在重新分配后,任何指向向量的指针都将无效。
这里发生的事情可能是这样的重新分配,因此一个指针将无效并且解除引用它将是未定义的行为,并且在您的情况下会导致崩溃。
答案 1 :(得分: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
的第一个元素,从而导致分段错误。
要解决您的问题,请不要将指针向量存储到另一个向量的对应元素!你可以只传递整个向量(最好通过引用,这样我们就不会产生复制的代价)并直接对元素本身进行操作。这肯定会为您节省一个小时的头痛,并且会产生更好,更短的代码。
答案 2 :(得分: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;
}
}