那一年滴掉的bug//物件的值莫名奇妙被改掉

  1. 那一年滴掉的bug//物件的值莫名奇妙被改掉
    1. 現象描述:
    2. Debug過程
      1. 「>>」的程式碼
      2. 「<<」的程式碼

那一年滴掉的bug//物件的值莫名奇妙被改掉

原文連結: https://darkblack01.blogspot.com/2013/02/blog-post_21.html
移植時的最後更新日期: 2013-02-21T12:27:17.094+08:00

現象描述:

視窗程式介面

  1. 選取白色9點、按下「>>」(add)
  2. 在右邊的List,任意選取特定數字3個(可不連續),按下「<<」(delete)
  3. 最後List呈現的卻是從後面刪除選取數目


程式記錄檔:
藍色為最終結果,白色為被刪除掉的部份,黑框為被選取的項目
由程式記錄檔可以看見,資料的確被刪除,但是物件本身的資料卻變得和原本的不一樣






Debug過程

問題發生在「delete」功能的Button所以,從這開始看。

「>>」的程式碼

void CMsrItemDlg::OnButtonAdd()
{
m_DNA = GetSelMsrItem(); //取得選取的量測項目

TranScripter Ts;
Ts.Trans(m_DNA, m_RNA); //轉錄

ListBoxUpdate(); //更新ListBox控制項
}

「<<」的程式碼

void CMsrItemDlg::OnButtonDel() 
{
LPINT buffer = new int[m_lstMsrItems.GetSelCount()]; //弄一個buffer,準備存放選擇好的東西
m_lstMsrItems.GetSelItems(m_lstMsrItems.GetSelCount(), buffer); //將選擇的選項,放進buffer

//將buffer弄成RNA
RNA temp;
m_dTxt.clear();
for (int it = 0; it < m_lstMsrItems.GetSelCount(); ++it)
temp.AddCell(m_RNA.At(buffer[it]+1));
//-------------------------------------------------------------------------------------
m_RNA.CutEqualCell(temp); //剪掉相同的
temp.Empty();

ListBoxUpdate(); //更新ListBox控制項

delete [] buffer;
}

程式記錄檔
第一步新增出來的陣列(位址、顏色、點)
19D586C, c(255, 255, 255), P(227, 128)    ←begin
19D58E0, c(255, 255, 255), P(683, 128)
19D5954, c(255, 255, 255), P(1139, 128)
19D59C8, c(255, 255, 255), P(227, 384)
19D5A3C, c(255, 255, 255), P(683, 384)
19D5AB0, c(255, 255, 255), P(1139, 384)
19D5B24, c(255, 255, 255), P(227, 640)
19D5B98, c(255, 255, 255), P(683, 640)
19D5C0C, c(255, 255, 255), P(1139, 640)
19D5C80                                                        ←end

選取的項目新增的另一個陣列(位址不同)
19F8314, c(255, 255, 255), P(683, 384)
19F8388, c(255, 255, 255), P(1139, 384)
19F83FC, c(255, 255, 255), P(227, 640)

由選取項的資料確定,OnButtonDel()程式碼的虛線以上是沒問題的!的確有選取到想選取的資料。接下來看看,虛線以下的部份,這部份主要就看兩個函式CutEqualCell()和ListBoxUpdate()
void RNA::CutEqualCell(RNA compData)
{
if (!compData.IsEmpty())//裡面這些不要修改,影響再次量測的資料擺放
{
std::vector<cartridge2>::iterator compItor, removeItor;

//remove & cut 在新的裡面,比對舊的,代表重覆,重覆量測去除掉
removeItor = End();
for (compItor = compData.Begin(); compItor != compData.End(); ++compItor)
removeItor = std::remove(Begin(), removeItor, *compItor);//確認compData的資料是沒錯的

m_CarChain2.erase(removeItor, End());
}
}

這個函式主要是由std::remove()和std::vector&lt;&gt;::erase()配合組成的,將卻刪除的元素移除。
追縱remove()所return的removeItor如果如下:
上圖:removeIter由init之後,執行一次std::remove()而移動一次;藍底項目為卻刪除的項目,紅框的部份可對照下圖,成功的保留下來。
下圖:執行完delete button之後的結果,是正確想要的?!
目前的證明CutEqualCell()的確依照設計做出了正確的動作!
繼續看看delete button下半段的另一個函數
void CMsrItemDlg::ListBoxUpdate()
{
m_lstMsrItems.ResetContent(); //清空List
m_btnDelItems.EnableWindow(m_RNA.Size());
m_btnOK.EnableWindow(m_RNA.Size());

if (m_RNA.Size())
for (std::vector<cartridge2>::iterator itor = m_RNA.Begin(); itor != m_RNA.End(); ++itor)
m_lstMsrItems.AddString(itor->GetDescrip());
}
可以看出,這只是重新將std::vector<>的內容增加到List而已,並沒有什麼特別的。

到目前為止,Debug的結果是delete button的動作是沒問題的,那問題在哪裡??
問題還是沒有定義出來呀!>口<

但是有一個地方有疑點,就是std::remove()的使用注意事項。
在使用STL的演算法時,需注意物件重載的運算子。

先看看這個物件有些什麼
class Cartridge2
{
UINT m_sequenceFrom; //依表格順序的序號
AreaKind m_sequenceArea; //依區域順序的序號
CPoint m_PointPosition; //點
COLORREF m_BkColor; //顏色
Bullet m_Data; //資料
CString m_Description; //中文描述

public:
BOOL operator==(const Cartridge2& vCar);
void operator= (const Cartridge2& vCar);
};
remove()的動作,需要比對是否相等!來看看cartridge2::operator==()
BOOL Cartridge2::operator==(const Cartridge2& vCar2)
{
return ( (GetPointPosi() == vCar2.GetPointPosi()) &&
(GetBkColor() == vCar2.GetBkColor() )
) ? TRUE : FALSE;
};
這個物件只要顏色和位置相同,就視為相同!
在相同顏色和相同點所更新到的資料也會不同,所以不須判斷(因為一定不一樣)
中文描述、順序的序號都是電腦生成,由顏色和點所判斷產生,所以也不需判斷。
結果:沒問題!

那問題在哪呀?!〒o〒

到現在,離問題出現已經過了兩天了,下班後找了朋友一起討論。
朋友直覺,檢查了operator==(),那operator=()呢?
那就檢查看看cartridge2::operator=()
void Cartridge2::operator= (const Cartridge2& vCar)
{
SetPointPosi(vCar.GetPointPosi());
SetBkColor(vCar.GetBkColor());

SetBullet(vCar.GetBullet());
}
看出來了嗎?賦值的動作只有資料、點、顏色;順序和描述並沒有隨著賦值的動作被copy過來。
這和之前遇到的問題現象是不是完全match呢!?

程式碼修改如下就Debug完成了
void Cartridge2::operator= (const Cartridge2& vCar)
{
SetDescrip(vCar.GetDescrip());
setSqncArea(vCar.getSqncArea());
setSqncFrm(vCar.getSqncFrm());

SetPointPosi(vCar.GetPointPosi());
SetBkColor(vCar.GetBkColor());

SetBullet(vCar.GetBullet());
}

就這樣,一個晚上的聚會解決了兩天以來的bug,我們又再度的拯救了地球,維護世界和平了。(開心~)