2010年9月11日 星期六

vector 內要放值還是放址?

vector 是 STL 其中之一非常好用的容器,用來替代1維的陣列管理物件是很常用的寫法,有一陣子我在看公司前輩寫的 code 發現一個怪怪的地方,那是一個跑在 Windows Mobile 平台的軟體,裡面有一些大概就是這樣子的一段 code


class CHugeClass
{
private:
  /*member variable*/
  /*大型資料結構,如圖片、影片之類的等*/
public
  /*member function*/
};

class CDlgHugeObjLib : CDialog
{
  vector<CHugeClass*> m_pvHugeObj;
};

void CDlgHugeObjLib::SelectAndInsertNewObj()
{
  CFile file;
  Byte *btObj;
  /*選擇一個大圖片、影片之類的檔案,並載入 btObj 中*/
  CHugeClass *pNewObj = new CHugeClass(btObj);
  HandleInsertObj(pNewObj);
}

void CDlgHugeObjLib::HandleInsertObj(CHugeClass *pHugeObj)
{
  m_pvHugeObj.push_back(pHugeObj);
}

void CDlgHugeObjLib::~CDlgHugeObjLib()
{
  freeObj();
}

void CDlgHugeObjLib:freeObj()
{
  for(i = 0; i < m_pvHugeObj.size(); i ++)
  {
    delete m_pvHugeObj[i];
    m_pvHugeObj[i] = NULL;
  }
}


那時我很好奇為什麼不寫 vector<CHugeClass> m_vHugeObj 這樣會讓程式單純很多,也不用自己去管記憶體釋放的問題,後來我才了解這是一種節省記憶體的技巧,若我們直接在 vector 裡面放實體物件的資料,一定逃不過要先建立一個 temp 實體,再把這個 temp 實體 push_back() 到 vector 裡面,例如


CHugeClass hc(bt);
m_vHugeObj.push_back(hc);


即便你寫


m_vHugeObj.push_back(CHugeClass(bt));


也是會被編譯器拆解成產生一個 temp,再將 temp 丟進去,而使用放位址的方式,就不需要借用一個 temp 實體的空間。

當然以上說法都是被限制在 Visual Studio 的 compiler 下的情況,有另一種解決方法被規範在 "C99" 中,C99 是標準 C 語言的再版,符合 C99 標準的 compiler 在這種情況下是不會產生 temp 空間的,


m_vHugeObj.push_back(CHugeClass(bt));


但很不幸,Visual Studio 一直到現在並沒有完全遵守 C99 過(現在指的是我寫這篇文章的時間,未來應該會),所以若是用 Visual Studio 的 comipler 編譯軟體就沒有這種聰明的功能,但我們還是可以利用上述的方法來讓我們的軟體比較沒那麼耗記憶體。

沒有留言:

張貼留言