2012-01-24 20 views
0

私は問題があります。すべてを試すのに約5時間を費やしていますが、それを正しく再現することさえできず、単純化された元のソースコードが含まれています。その程度までお詫び申し上げますが、私がこれまでに知り得たすべての関連情報を含めたかったのです。これは私が完全に無力で、あなたの助けを親切に要求している数回のうちの1つです。どんなアイディアも大歓迎です。また、問題に少なくともいくらかの光をもたらすことができるコメント。この場合の動作は私にとって完全な謎です。非constメソッドを呼び出さずにプライベートメンバーを変更するにはどうすればよいですか?

私はUbuntuのQtCreatorでプログラミングしています。私は真の解に進化するべき候補解の集団を使って数学的問題を解決するためのフレームワークを開発しようとしています。

関わる3つのクラスがあります:人口、PopulationMemberと問題:

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

通常私のプログラムは、人口がそのさまざまなメソッドを呼び出しループで実行されますが。それらの1つはPopulation :: evaluate()です。 Populationの新しいメソッドを導入するまで私のプログラムは素晴らしかったです。

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

}

デバッグ:プリントアウト ADDRESは0xbffff628あります。これは、前の10 *人口_-> 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()> 

私は最後の命令での関数の呼び出し中に入ります。私はこれを行う瞬間、問題のすべての属性_は私のデバッガによればアクセスできない。 この時点ではすべてが失われています。

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

常に発生します。私が3つのすべてのクラスのサイズが100未満であるので、これはもっと難解です。

voidの内部でプログラムがクラッシュする問題:: evaluate(PopulationMember &)const;メソッドを呼び出すことができます。

EDIT:

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

は、問題を単純化することができます方法はありますか? Clone()メソッドを見せてもらえますか? –

+0

valgrindを試しましたか? –

+0

人口母集団::クローン()const { 人口temp(* this); 戻り値。 } –

答えて

1
Population Population::clone() 
{ 
    Population temp(*this); 
    return temp; 
} 

あなたは周りPopulation -instancesにかなりをコピーしている: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&の値はスタックに格納され、ループが終了すると削除されますが、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_); 
} 
+0

ありがとう、これも私を悩ましていましたが、temp内のPopulationMembersはすべてヒープ上に作成されています。 tempオブジェクトが有効範囲外になるとPopulationMembersは削除されません –

+0

私にとっては心配なのは、ポインタの問題がちょうど変わったということです。それは起こるべきではありません。それが私を殺している理由です –

+0

説明したようにオフセットが変化した場合、 'this'はもはや有効ではない可能性があります。 'Problem * problem_;'を 'const Problem&problem_'にリファクタリングしてみてください。これはいくつかのコンストラクタも変更することを意味しますが、この方法では削除されないことを確認できます。問題が(期待通りに)続く場合、削除された 'Population'を指し示す' PopulationMember'があるかもしれません - 'Population * population_'を' const Population&population_'にリファクタリングして、まだメンバーが呼び出されている人口を誤って削除してしまうことはありません。ちょっと推測;) – Coder02

関連する問題