九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Visual C++及C++中的智能指針應(yīng)用分析
Visual C++及C++中的智能指針應(yīng)用分析
2008年03月28日 星期五 16:59
前段時(shí)間,在查控件的內(nèi)存泄露時(shí),最終找出一個錯誤:在使用XMLDom(COM)時(shí),由于重復(fù)使用某接口指針前未釋放Dispatch指針(Release),而導(dǎo)致內(nèi)存泄露,而此類錯誤(如同BSTR類型的泄漏),VC的調(diào)試器和Bondcheck均無能為力。解決辦法,似乎只有細(xì)心一途。

  但只要稍稍仔細(xì)看看,就可發(fā)現(xiàn),實(shí)際上如果正確使用VC提供的智能指針,是可以避免此問題的。

  另外,一直為Java程序員津津樂道的內(nèi)存使用無需管理的優(yōu)勢,一直知道用C++的智能指針可以模擬。但一直沒實(shí)際動手做過,趁此分析之機(jī),用C++簡單包裝了一個。反正粗看之下,可以達(dá)到與Java類似的效果,當(dāng)然,C++的對象更高效且節(jié)省內(nèi)存。

  就以上所提到的,時(shí)間關(guān)系,我只能簡單羅列幾點(diǎn),代碼應(yīng)該是正確的(但未檢查)。前后文沒什么邏輯關(guān)系,但如果要進(jìn)一步應(yīng)用C++的智能指針,相信會起到拋磚引玉之效。

  一:關(guān)于糾錯,MFC和ATL中智能指針的應(yīng)用

  1:在Windows中如何方便的查看當(dāng)前進(jìn)程使用的內(nèi)存。

  雖然代碼簡單,但對糾錯時(shí)有大用處,不用不停的通過切換任務(wù)管理器來查看內(nèi)存使用。代碼如下:

UINT C_BaseUtil::getProcessMemoryUsed()
{
 UINT uiTotal = 0L;
 HANDLE hProcess = ::GetCurrentProcess();
 PROCESS_MEMORY_COUNTERS pmc;
 if(::GetProcessMemoryInfo(hProcess,&pmc,sizeof(pmc)))
  uiTotal = pmc.WorkingSetSize;
 return uiTotal;
}

  注意:由于內(nèi)存使用會是一個不穩(wěn)定的過程,所以,需要在程序穩(wěn)定時(shí)進(jìn)行調(diào)用,才能準(zhǔn)確。

  2:在使用Com的Dispatch指針時(shí),如果不使用COM智能指針,容易出現(xiàn)的錯誤。

  2.1:忘記在所有出口釋放指針。
  
  如:

IXMLDOMDocument *pDoc = NULL;
CoCreateInstance(...)
……
pDoc->Release();

  錯誤:如果中間代碼發(fā)生異常,則pDoc未能正常釋放,造成內(nèi)存泄露。

  2.2:重復(fù)使用同一指針變量,導(dǎo)致中間生成的Dispatch指針未能釋放。

IXMLDOMNode *pNode = NULL;
if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &pNode)) || pNode==NULL)
throw(_T("selectSingleNode failed!"));
if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &pNode)) || pNode==NULL)
throw(_T("selectSingleNode failed!"));

  錯誤:pNode未釋放就開始第二次調(diào)用,造成內(nèi)存泄露?;蛘哳愃苝Node = pNode2的這種寫法,也隨手就出問題了。必須調(diào)用if(pNode) {pNode->Release();pNode=NULL;}

  3:使用MFC提供的Com智能指針解決上述問題。

  注意:可通過查看源碼,看到#import生成的智能指針的原型是_com_ptr_t。

  3.1:

IXMLDOMDocumentPtr docPtr = NULL;
docPtr.CreateInstance(...)
……

  這下不會有問題了,因?yàn)閐ocPtr在析構(gòu)時(shí)會有正確的釋放處理。

  3.2:

IXMLDOMNodePtr nodePtr = NULL;
if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &nodePtr)) || nodePtr==NULL)
throw(_T("selectSingleNode failed!"));
if(FAILED(pDoc->selectSingleNode(_bstr_t("Workbook"), &nodePtr)) || nodePtr==NULL)
throw(_T("selectSingleNode failed!"));

  不會出錯了,因?yàn)開com_ptr_t重載了&操作符,在取指針時(shí),有如下操作,嘿。

Interface** operator&() throw()
{
 _Release();
 m_pInterface = NULL;
 return &m_pInterface;
}

  3.3: nodePtr = nodePrt2 ,也不會有問題:

  仔細(xì)查看源碼,在=操作符中會調(diào)用Attach,而Attach的做法是:會先調(diào)用_Release();

  3.4:再看看值傳遞:拷貝構(gòu)造函數(shù)如下

template<> _com_ptr_t(const _com_ptr_t& cp) throw()
: m_pInterface(cp.m_pInterface)
{
 _AddRef();
}

  嗯,也不會有問題。

  3.5:最后我們也總結(jié)一下使用COM智能指針時(shí)的注意事項(xiàng):

  ·不要在Com智能指針的生命期如果在::CoUninitailize之后,那請?jiān)谡{(diào)用::CoUninitailize之前,強(qiáng)制調(diào)用MyComPtr = NULL;達(dá)到強(qiáng)制釋放的目的。否則會出錯。

  ·不要混用智能指針和普通Dispatch指針,不要調(diào)用MyComPtr->Release(),這違背智能指針的原意,會在析構(gòu)時(shí)報(bào)錯。

  4:使用ATL提供智能指針:CComPtr或是CComQIPtr.

  如果不使用MFC框架,要自已包裝IDispatch,生成智能指針,還可以使用ATL提供的智能指針。查看源碼,并參照《深入解析ATL》一書,發(fā)現(xiàn)實(shí)現(xiàn)與_com_ptr_t大同小異,效果一致。

  二:引申一下,我們來看看C++的智能指針

  1:說到智能指針,我們一定要看看標(biāo)準(zhǔn)C++提供的auto_ptr。而auto_ptr的使用是有很多限制的,我們一條一條來細(xì)數(shù):

  1.1:auto_ptr要求一個對象只能有一個擁有者,嚴(yán)禁一物二主。

  比如以下用法是錯誤的。

classA *pA = new classA;
auto_ptr<classA> ptr1(pA);
auto_ptr<classA> ptr2(pA);

  1.2:auto_ptr是不能以傳值方式進(jìn)行傳遞的。

  因?yàn)樗袡?quán)的轉(zhuǎn)移,會導(dǎo)致傳入的智能指針失去對指針的所有權(quán)。如果要傳遞,可以采用引用方式,利用const引用方式還可以避免程序內(nèi)其它方式的所有權(quán)的轉(zhuǎn)移。就其所有權(quán)轉(zhuǎn)移的做法:可以查看auto_ptr的拷貝構(gòu)造和=操作符的源碼,此處略。

  1.3:其它注意事項(xiàng):

  ·不支持?jǐn)?shù)組。

  ·注意其Release語意,它沒有引用計(jì)數(shù),與com提供的智能指針不同。Release是指釋放出指針,即交出指針的所有權(quán)。

  ·auto_ptr在拷貝構(gòu)造和=操作符時(shí)的特珠含義決定它不能做為STL標(biāo)準(zhǔn)容器的成員,

  好了,看了上面的注意事項(xiàng),特別是第三條,基本上可以得出結(jié)論:在實(shí)際應(yīng)用場合,auto_ptr基本沒什么應(yīng)用價(jià)值的。

  2:如何得到支持容器的智能指針。

  我們利用auto_ptr的原型,制作一個引用計(jì)數(shù)的智能指針,則時(shí)讓它支持STL容器的標(biāo)準(zhǔn)。實(shí)現(xiàn)代碼很簡單,參照了《C++標(biāo)準(zhǔn)程序庫》中的代碼,關(guān)鍵代碼如下:

template<class T>
class CountedPtr {
 T * ptr;
 long * counter;
 public:
  //構(gòu)造
  explicit CountedPtr(T* p = NULL)
  :ptr(p),count(new long(1){}
  //析構(gòu)
  ~CountedPtr() {Release();}
  //拷貝構(gòu)造
  CountedPtr(cont CountedPtr<T>& p)
  :ptr(p.ptr),count(p.count) {++*counter;}
  //=操作符
  CountedPtr<T>& operator= (const CountedPtr<T>& p) {
   if(this!=&p) {
    Release();
    ptr=p.ptr;
    counter=p.counter;++*counter;
   }
   return *this;
  }
  //其它略
  ....
 private:
  void Release() {
   if(--*counter == 0) {
    delete counter;
    delete ptr;
   }
  }
}

  好了,這樣,當(dāng)復(fù)制智能指針時(shí),原指針與新指針副本都是有效的,這樣就可以應(yīng)用于容器了。現(xiàn)在,通過CountedPtr包裝的C++對象,是不是和Java的對象類似了呢,呵呵。只要再加上一些必要的操作符,它就可以作為容器中的共享資源來使用了。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
auto_ptr智能指針
WebKit里的RefPtr和PassRefPtr
C++二叉樹結(jié)構(gòu)的建立與基本操作
C語言指針5分鐘教程
C語言指針導(dǎo)學(xué)(2)
2013搜狗校園招聘筆試題
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服