指向父的指针无故更改
pointer to parent changes for no reason
我有两个类这样说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;
}
当我 运行 此代码时,我得到这些结果:
Before: 1
After: 16276538888567495168
parent changed
Before: 2
After: 3
parent the same
parent the same
finish
如您所见,问题是有时父指针在 push_back 之后会发生变化。我尝试在检查父指针 push_back 之前和之后调试代码。在此之前它是一些地址,但在那之后它是其他东西加上这段文字:这似乎有段错误。
这里问题的关键似乎是 B 的每个实例的大小。如果我将 'data' 的大小更改为任何小于 14 的值,程序运行正常,但对于 14 或更高的值,就会发生这种情况。
这看起来很奇怪,我花了好几天时间来解决这个问题。你能告诉我为什么会这样吗?
我认为 parent
指针没有变化。据我所知,错误是在 foo()
中你遍历 bVec
在每次迭代中调用 size()
,而 bVec
的大小在调用 addNewB
.
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 在这里被更改,其中包含特定 B
对象的 this
,即 运行 代码。
void A::foo() {
for(int i=0; i<bVec.size(); i++)
bVec[i].addNewB();
}
bVec
在此调用中更改。在超过预分配堆 space 的 push_back()
调用中(可能像这个),vector
需要重新分配堆内存并将所有内容移动过来。在移动过程中,vector
销毁了 B
对象 运行 该代码。控制已恢复到具有过时 this
的 B
代码,因此 this->parent
现在包含垃圾。
回溯大概是这样的:
A::foo()
B::addNewB()
vector<B>::reallocate() //destroys previous frame's B
向量分配的 space 比 size()
建议的多,您可以找到
用 capacity()
退出,用 reserve()
改变。这意味着,当
你 push_back()
有成长的空间。当那个 space 用完时,
整个向量重新分配更多 space,此过程移动现有
内存中的对象。这就是为什么你得到指向对象的指针
不再存在。
vector 始终将其所有对象连续(顺序)保存在内存中。
一个可能的解决方案是 reserve
足够 space 这样
重新分配永远不会发生,另一个切换到 std::list
.
另请注意,不仅仅是您的父指针会失效,因为
你
正在从所述向量中的对象的方法触发向量重新分配,
您还使用了无效的 this
指针。
我有两个类这样说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;
}
当我 运行 此代码时,我得到这些结果:
Before: 1
After: 16276538888567495168
parent changed
Before: 2
After: 3
parent the same
parent the same
finish
如您所见,问题是有时父指针在 push_back 之后会发生变化。我尝试在检查父指针 push_back 之前和之后调试代码。在此之前它是一些地址,但在那之后它是其他东西加上这段文字:这似乎有段错误。
这里问题的关键似乎是 B 的每个实例的大小。如果我将 'data' 的大小更改为任何小于 14 的值,程序运行正常,但对于 14 或更高的值,就会发生这种情况。
这看起来很奇怪,我花了好几天时间来解决这个问题。你能告诉我为什么会这样吗?
我认为 parent
指针没有变化。据我所知,错误是在 foo()
中你遍历 bVec
在每次迭代中调用 size()
,而 bVec
的大小在调用 addNewB
.
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 在这里被更改,其中包含特定 B
对象的 this
,即 运行 代码。
void A::foo() {
for(int i=0; i<bVec.size(); i++)
bVec[i].addNewB();
}
bVec
在此调用中更改。在超过预分配堆 space 的 push_back()
调用中(可能像这个),vector
需要重新分配堆内存并将所有内容移动过来。在移动过程中,vector
销毁了 B
对象 运行 该代码。控制已恢复到具有过时 this
的 B
代码,因此 this->parent
现在包含垃圾。
回溯大概是这样的:
A::foo()
B::addNewB()
vector<B>::reallocate() //destroys previous frame's B
向量分配的 space 比 size()
建议的多,您可以找到
用 capacity()
退出,用 reserve()
改变。这意味着,当
你 push_back()
有成长的空间。当那个 space 用完时,
整个向量重新分配更多 space,此过程移动现有
内存中的对象。这就是为什么你得到指向对象的指针
不再存在。
vector 始终将其所有对象连续(顺序)保存在内存中。
一个可能的解决方案是 reserve
足够 space 这样
重新分配永远不会发生,另一个切换到 std::list
.
另请注意,不仅仅是您的父指针会失效,因为
你
正在从所述向量中的对象的方法触发向量重新分配,
您还使用了无效的 this
指针。