我有个问题。我花了大约5个小时尝试所有东西,但我甚至无法正确复制,所以我包含了简化的原始源代码。我对此表示歉意,但我想把到目前为止我发现的所有相关信息都包括在内。这是我为数不多的几次感到完全无能为力并恳请你的帮助。欢迎提出任何想法。还有任何评论,至少可以给事情带来一些启示。这种情况下的行为对我来说完全是个谜
我在Ubuntu中用QtCreator编程。我正试图开发一个框架,使用候选解决方案的群体来解决数学问题,这应该会演变成真正的解决方案。
共涉及3个类:人口、人口成员和问题:
class PopulationMember
{
QVector<Number> x_;
QVector<Number> y_;
Population* population_; EDIT: Sorry, this is a pointer
void evaluate();
friend class Population;
};
class Population
{p
public:
QList<PopulationMember*> members_; // created on the heap
Problem* problem_; // created on the heap
const Problem* readProblem() const;p
void evaluate();
void report() const;
...
};
class Problem
{
public:
void evaluate(PopulationMember&)const;
};
通常,我的程序在循环中运行,在循环中,总体调用它的各种方法。其中之一是Population::evaluate()。我的程序运行得很好,直到我引入了一些新的人口方法。
for (int i = 1; i != 101; ++i)
{
Population->evaluate();
Population->someMethod1();
Population temp = Population->clone();
temp->someMethod2();
Population->append(temp);
Population->someNewMethod();
Population->someSorting();
if (i % 10 == 0)
Population->report();
}
然后我在程序中间得到一个分段错误。最奇怪的是,它只发生在10个循环之后,在population执行report()之后。同样,经过一些实验,当我从report()方法中排除了所有需要动态分配某种排序(字符串)的操作时,我没有得到错误。相反,当我禁用排序方法(使用std::sort或qSort)时,问题就停止了。此外,当我离开临时人员完成的操作时,也没有问题。所以我开始调试这个程序。我让它完成了10个循环,并开始逐步调试。我进入了Population->evaluate();
void Population::evaluate()
{
for (Iterator it = begin(); it != end(); ++it)
{
std::cout << problem_; // debug see bellow:
(*it) -> evaluate(); // If I change to problem_->evaluate(**it); the program works.
}
}
调试:打印出来的地址是0xbffff628。这与之前的10*population_->members_.count()打印输出相同。
我进入(*it)->evaluate();在这里我切换到汇编代码:
864 (*it) -> evaluate();
0x805380c <+122>: lea -0x10(%ebp),%eax
0x805380f <+125>: mov %eax,(%esp)
0x8053812 <+128>: call 0x8055d84 <QList<PopulationMember*>::iterator::operator*() const>
0x8053817 <+133>: mov (%eax),%eax
0x8053819 <+135>: mov %eax,(%esp)
0x805381c <+138>: call 0x805ae08 <PopulationMember::evaluate()>
我在最后一条指令处进入函数调用内部。在我这样做的那一刻,根据我的调试器,problem_中的所有属性都变得不可访问。在这一点上,一切都失去了。
void PopulationMember::evaluate()
{
population_ -> readProblem() -> evaluate(*this);
}
135 {
0x805ae08 <+000>: push %ebp
0x805ae09 <+001>: mov %esp,%ebp
0x805ae0b <+003>: sub $0x18,%esp
136 population_ -> readProblem() -> evaluate(*this);
0x805ae0e <+006>: mov 0x8(%ebp),%eax
0x805ae11 <+009>: mov 0x4(%eax),%eax
0x805ae14 <+012>: mov %eax,(%esp)
0x805ae17 <+015>: call 0x8051bc4 <Population::readProblem() const>
0x805ae1c <+020>: mov 0x8(%ebp),%edx
0x805ae1f <+023>: mov %edx,0x4(%esp)
0x805ae23 <+027>: mov %eax,(%esp)
0x805ae26 <+030>: call 0x804e962 <Problem::evaluate(PopulationMember&) const>
137 }
0x805ae2b <+035>: leave
0x805ae2c <+036>: ret
0x805ae2d nop
const Problem* Population::readProblem() const
{
std::cout << problem_ << std::endl; // debug see bellow:
return problem_;
}
调试:最后,问题指向的地址变为0xbffff780,而不是0xbffff228。增加344
这种情况总是发生。增量为344。如果我在程序中做一些小的更改,地址就会改变,但这两个地址之间的差异仍然是344。这更令人费解,因为我三个班的人数都不到100人。
程序在void内部崩溃问题::evaluate(PopulationMember&)const;方法。
编辑:
Population Population::clone()
{
Population temp(*this);
return temp;
}
Population::Population(const Population& population)
{
this->setProblem(population.problem_);
Population::ConstIterator cit;
for (cit = population.constBegin(); cit != population.constEnd(); ++cit)
this->addCopy(*cit);
this->ownsMembers_ = true;
}
void Population::addCopy (PopulationMember* populationMember)
{
PopulationMember *temp = new PopulationMember(*populationMember); // Memberwise
temp -> population_ = this;
members_.push_back(populationMember);
}
Population::~Population()
{
if (ownsMembers_)
foreach (PopulationMember* X, members_)
delete X;
}
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
members_.append(population.members_);
population.ownsMembers_ = false;
}
else
members_.append(population.members_);
}
Population Population::clone()
{
Population temp(*this);
return temp;
}
您正在大量复制Population
-实例:1。您正在按值2返回本地副本。通过分配到另一个本地再次复制
Population temp = Population->clone();
所有这些实例都获得指向PopulationMember
的指针,而ownsMembers_
总是设置为true——这看起来有点可疑,您可能需要在析构函数/构造函数中使用断点进行调试,以了解每个填充及其成员的生命周期。
EDIT:附加方法
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
members_.append(population.members_);
population.ownsMembers_ = false;
}
...
这意味着成员们再也不能指向正确的人口了!Population&
的值存储在堆栈中,并在for
循环结束后被删除,但PopulationMembers仍然指向这些Population。
编辑:修复
请试试这个:
void Population::append(Population& population)
{
if (population.ownsMembers_)
{
for (cit = population.constBegin(); cit != population.constEnd(); ++cit)
(*cit)-> population_ = this;
population.ownsMembers_ = false;
}
members_.append(population.members_);
}