gpt4 book ai didi

c++ - 如何在不调用非常量方法的情况下更改私有(private)成员?

转载 作者:行者123 更新时间:2023-11-28 08:11:18 29 4
gpt4 key购买 nike

我有一个问题。我花了大约 5 个小时尝试一切,但我什至无法正确重现它,所以我包含了简化的原始源代码。对于范围,我深表歉意,但我想包括到目前为止我发现的所有相关信息。这是我感到完全无能为力并恳请您帮助的少数几次之一。欢迎任何想法。还有任何至少可以为此事带来一些启示的评论。这种情况下的行为对我来说完全是个谜。

我在 Ubuntu 的 QtCreator 中编程。我正在尝试开发一个框架来使用候选解决方案的群体来解决数学问题,这些候选解决方案应该演变成真正的解决方案。

涉及 3 个类:Population、PopulationMember 和 Problem:

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 次循环之后,即人口执行 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_;
}

调试:最后,problem_ 指向的地址变为 0xbffff780 而不是 0xbffff628。增量344

这种情况经常发生。增量是 344。如果我在程序中做一些小改动,地址会改变,但这两个地址之间的差值仍然是 344。这更令人费解,因为我的三个类的大小都小于 100。

程序在 void Problem::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 - 这看起来有点可疑,您可能希望在析构函数/构造函数中使用断点进行调试找出每个种群及其成员的生命周期。

编辑:追加方法

void Population::append(Population& population)
{
if (population.ownsMembers_)
{
members_.append(population.members_);
population.ownsMembers_ = false;
}
...

这意味着成员不再指向正确的人口! Population& 的值存储在堆栈中,并在 for 循环结束后被删除,但 PopulationMembers 仍然指向这些 Populations。

编辑:修复

请试试这个:

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_);
}

关于c++ - 如何在不调用非常量方法的情况下更改私有(private)成员?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8988321/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com