Как изменить приватный член, не вызывая неконстантный метод? - PullRequest
0 голосов
/ 24 января 2012

У меня проблема.Я потратил около 5 часов, пытаясь все, но я даже не смог воспроизвести его должным образом, поэтому я включил упрощенный исходный код.Я прошу прощения за степень, но я хотел включить всю соответствующую информацию, которую я узнал до сих пор.Это один из немногих случаев, когда я чувствую себя совершенно бессильным и прошу вашей помощи.Любые идеи приветствуются.Также любые комментарии, которые могут пролить свет на этот вопрос.Поведение в этом случае является для меня полной загадкой.

Я программирую в QtCreator в Ubuntu.Я пытаюсь разработать структуру для решения математических задач, используя решения «Популяция кандидатов», которые должны превратиться в истинное решение.

В нем участвуют 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 ::valu ().Моя программа работала отлично, пока я не представил некоторые новые методы народонаселения.

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 (), я не получаю ошибкуИ наоборот, когда я отключаю метод сортировки (использует либо std :: sort, либо qSort), проблема прекращается.Также, когда я оставляю действия, выполняемые временным населением, проблем не возникает.И я начал отлаживать программу.Я позволил ему завершить 10 циклов и начал отлаживать шаг за шагом.Я вошел в Population- >valu ();

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.
}

}

debug: Распечатаны адреса 0xbffff628.Это то же самое, что и предыдущие 10 * населения _-> members_.count () распечаток.

Я вхожу в (* it) - >valu ();Здесь я переключаюсь на ассемблерный код:

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

debug: Наконец адрес, на который указывает проблема_, становится 0xbffff780 вместо 0xbffff628.Приращение 344

Это происходит всегда.Приращение составляет 344. Если я внесу небольшие изменения в программу, адрес изменится, но разница между этими двумя адресами останется 344. Это тем более удивительно, поскольку размер всех моих трех классов меньше 100.

Сбой программы в пустоте. Problem :: define (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_);
 }

1 Ответ

1 голос
/ 24 января 2012
 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 по-прежнему указывают на эти совокупности.

Редактировать: Исправить

пожалуйста, попробуйте это:

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