父指针无缘无故变化

时间:2015-01-24 09:27:08

标签: c++ pointers segmentation-fault

我有两个班级说A& B喜欢这样:

// A.h
#include <iostream>
#include <vector>
using namespace std;

#ifndef A_H_
#define A_H_

#include "B.h"

class A {
public:
    std::vector<B> bVec;
    A();
    void foo();
virtual ~A();
};
#endif /* A_H_ */

//--------------------
// A.cpp
#include "A.h"

A::A() {
    B b(this);
    bVec.push_back(b);
}

void A::foo() {
    for(int i=0; i<bVec.size(); i++)
        bVec[i].addNewB();
}

A::~A() {
}


//--------------------
// B.h

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

#ifndef B_H_
#define B_H_

class A;

class B {
public:

    A* parent;
    double data[15];

    B(A* p);
    void addNewB();
    virtual ~B();
};

#endif /* B_H_ */

//--------------------
// B.cpp

#include "B.h"
#include "A.h"

B::B(A* p) {
    parent = p;
}

void B::addNewB() {
    A* tmpA = parent;
    if(parent->bVec.size() < 3)
    {
        std::cout<< "Before: " << parent->bVec.size() << '\n';
        parent->bVec.push_back(B(parent));
        std::cout<< "After: " << parent->bVec.size() << '\n';
    }
    if(tmpA == parent)
        cout<< "parent the same\n";
    else
        cout<< "parent changed\n";
}

B::~B() {
}

//--------------------
// main.cpp

#include <stdio.h>
#include "A.h"

int main()
{
    A a;
    a.foo();
    std::cout<< "finish\n";
    return 0;
}

当我运行此代码时,我得到以下结果:

  

之前:1

     

之后:16276538888567495168

     

父改变了

     

之前:2

     

之后:3

     

父母相同

     

父母相同

     

光洁度

您可以看到的问题是,有时父指针会在push_back之后发生变化。我尝试在push_back之前和之后调试代码我检查了父指针。在那之前它是一些地址,但之后它是另外的东西加上这个文本:它似乎有一些分段错误。

这里问题的关键似乎是B的每个实例的大小。如果我将'data'的大小更改为低于14的任何值,程序工作正常但是14或更高时会发生这种情况。

这看起来非常奇怪,我花了几天时间与之抗争。你能告诉我为什么会这样吗?

3 个答案:

答案 0 :(得分:5)

void B::addNewB() {
    A* tmpA = parent;
    if(parent->bVec.size() < 3)
    {
        std::cout<< "Before: " << parent->bVec.size() << '\n';
        parent->bVec.push_back(B(parent));
        std::cout<< "After: " << parent->bVec.size() << '\n';
    }
    if(tmpA == parent)
        cout<< "parent the same\n";
    else
        cout<< "parent changed\n";
}

此处更改了bVec,其中包含运行代码的特定this对象的B

void A::foo() {
    for(int i=0; i<bVec.size(); i++)
        bVec[i].addNewB();
}
此次调用已更改

bVec。在超过预分配堆空间的push_back()调用(可能是这样的),vector需要重新分配堆内存并将所有内容移动。在移动过程中,vector销毁了运行该代码的B对象。控制已恢复为B代码,其中包含过时的this,因此this->parent现在包含垃圾。

以下是回溯可能的样子:

A::foo()
B::addNewB()
vector<B>::reallocate() //destroys previous frame's B

答案 1 :(得分:1)

向量分配的空间比size()建议的空间多,您可以找到 使用capacity()退出,并使用reserve()进行更改。这意味着,当时 你push_back()还有成长的空间。当那个空间耗尽时,
整个向量重新分配更多空间,这个过程移动现有的 记忆中的物体。这就是为什么你得到指向对象的指针的原因 不再存在了。
向量始终将所有对象连续(顺序)保存在内存中。

一种可能的解决方案是reserve足够的空间,以便a 重新分配永远不会发生,另一个切换到std::list

另请注意,不只是您的父指针会失效,因为 你
从所述向量中的对象的方法触发向量重新分配,
您还使用了无效的this指针。

答案 2 :(得分:0)

我不认为parent指针会发生变化。据我所知,错误是在foo()中,您在每次迭代中迭代bVec调用size(),而bVec的大小在调用{addNewB之后发生变化{1}}。