Categories
程式設計 資訊科學

C++ 動態配置記憶體心得(下)

續上集…

  • STL container 的 clear 真的就 clear 乾淨了嗎?

    相信很多人在寫 C++ 時,都會想利用 STL 來省去一些造輪子的麻煩,其中最常被使用的就是像 std::vectorstd::list 這類的 container,常常有人就拿它們來當 variable-length 的 array 來解決問題。

    然後可能就會有像這樣子的 code 出現:
    [code lang=”cpp”]

    std::vector vec;

    MyClass* pObj = new MyClass(…);
    vec.push_back(pObj);


    // 用完 vec 之後,試圖把它清除掉
    vec.clear();
    [/code]
    很多人以為這樣寫,clear() method 就會幫你把曾經放進去的 element 給清乾淨了,可惜並不是這麼美好!沒錯,clear() 的確是會把 vec 裡的 elements 都清掉沒錯,但你有沒有注意到,vec 的 element type 是 MyClass*,是個指標的資料型態,也就是說:呼叫 clear() method 清掉了這些個指標,但卻沒有清掉指標所指到的 object!所以最起碼你應該這麼寫:
    [code lang=”cpp”]
    // 以 iterator 走訪整個 vec 裡的元素,
    // 然後一一 delete 掉指到的 object
    for (std::vector::iterator iter = vec.begin(); iter != vec.end(); ++iter)
    {
    delete *iter;
    }
    vec.clear();
    [/code]
    如果你有大量使用 STL 習慣的人,一定要小心 container 裡的 element 是不是真的都清乾淨了。

  • 如果你很懶,請愛用 std::auto_ptr

    之前有提到 new 過就不要忘記 delete 它,但如果你常常忘記 delete 的話,不妨用 std::auto_ptr 來幫你吧!std::auto_ptr 是一個 smart pointer ,它雖然是一個 templated class,但它的 object 用起來就好像一般的指標一樣,差別在於:當這個 object 被 destroy 時,它會檢查指到的記憶體是不是經由 new 所配置來的,如果是,就順便清掉!下面就用簡單的例子來說明:
    [code lang=”cpp”]
    #include // 要引入 memory 標頭檔

    {
    std::auto_ptr pObj(new MyClass());

    // 這時就可以使用 pObj->xxx() 來呼叫 method,
    // 就好像你用 MyClass *pObj; 宣告一樣。

    // 此時 pObj 被 destroy 了,
    //而它指到的記憶體也會被釋放。
    }

    [/code]
    看起來方便多了,是吧?不過沒用過 std::auto_ptr 的人要注意到,它是沒辦法經由 copy assignment 來與另一個 std::auto_ptr object 來 share 指到的記憶體位置。比方說下列的 code 就會使 p1 最後指到 null
    [code lang=”cpp”]

    std::auto_ptr p1(new MyClass());
    std::auto_ptr p2;
    p2 = p1;

    [/code]
    這樣 p2 會指到原本 p1 指到的記憶體,但卻讓 p1 指到 null 了。如果你想要使用可以 share 的 smart pointer,或許你可以參考 boost library 裡的 shared_pointer,或是等待 C++ 2.0 的標準函式庫(詳情可見 TR1 draft

簡單地寫了最近常碰到的問題,歡迎各方高手不吝賜教。:)

5 replies on “C++ 動態配置記憶體心得(下)”

不好意思,我記得autoptr會無差別delete他所存的指標耶@@
#include
#include
class Dummy
{
public:
Dummy()
{
std::cout << “A dummy created” << std::endl;
}
~Dummy()
{
std::cout << “Dummy deleted” << std::endl;
}
};
void dummyFun(Dummy* ptrDummy)
{
std::cout << “Function started” << std::endl;
std::auto_ptr aPtr(ptrDummy);
std::cout << “Funtion ended” << std::endl;
}
int main()
{
std::cout << “Program started” << std::endl;
Dummy iAmDummy;
dummyFun(&iAmDummy);
std::cout << “Program ended” << std::endl;
return 0;
}
在VC2008 express中如果在debug build中在auto_ptr嘗試delete從main傳過去的資料VC2008會自動break報告問題出現,而在release build中在dummyFun會被delete一次而離開main再destruct一次。
是因為這是VC2008用的政策嗎?

因為 debug build 會給比較嚴謹的 memory routine.
你嘗試因為 auto_ptr 去 delete heap-based 的指標,會給錯誤
而 release build 就沒有那麼嚴謹,通常簡單的程式會繼續跑下去 直到發生到不可回復的錯誤為止。

Leave a Reply

Your email address will not be published. Required fields are marked *