2012-01-24 31 views
0

我有一個問題。我花了大約5個小時嘗試一切,但我甚至無法正確再現它,所以我包括了簡化的原始源代碼。我對此表示歉意,但我想包括迄今爲止發現的所有相關信息。這是我感覺完全沒有力量的少數時間之一,並請求你的幫助。任何想法都歡迎。此外,任何意見都可以爲此事帶來至少一些啓示。這種情況下的行爲對我來說是完全神祕的。如何在不調用非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; 
}; 

通常我的程序循環,那裏的人口調用它的各種方法運行。其中之一是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(); 
} 

然後我在程序中間出現分割錯誤。最奇怪的是,只有在執行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 * 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_); 
} 
+2

是否有可以簡化問題的任何方式?你能告訴我們克隆()方法嗎? –

+0

你試過valgrind嗎? –

+0

人口人口:: clone()const { Population temp(* this); return temp; } –

回答

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

您正在複製周圍Population -instances頗有幾分:用

分配到另一個地方再次1.你是值回本地副本,複製2
Population temp = Population->clone(); 

所有這些實例指向PopulationMemberownsMembers_總是設置爲真 - 這看起來很腥,你可能想deb ug在你的析構函數/構造函數中帶有斷點,以查明每個人口及其成員的生命週期。

編輯:追加方法

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

謝謝,這也讓我感到困擾,但是temp中的所有Population成員都是在堆上創建的。當臨時對象超出範圍時,它不會刪除其PopulationMembers –

+0

對於我來說,令人難以置信的是指針問題只是改變了。它不應該發生。這就是爲什麼它正在殺死我 –

+0

如果偏移量如你所描述的那樣變化,那麼很有可能'this'不再有效。請嘗試將'Problem * problem_;'重構爲'const Problem&problem_' - 這意味着也要更改一些構造函數,但這樣可以確保它不會被刪除。如果問題依然存在(如預期的那樣),那麼可能有一個'PopulationMember'指向已刪除的'Population' - 您應該能夠將'Population * population_'重構爲'const Population&population_'以確保您不會意外刪除仍有議員的人口。只是猜測一下;) – Coder02

相關問題