2010-06-01 95 views
7

我不明白爲什麼下面的代碼會產生內存泄漏(我正在使用帶有靜態類實例的boost::shared_ptr)。有人能幫助我嗎?C++靜態類和shared_ptr內存泄漏

#include <crtdbg.h> 
#include <boost/shared_ptr.hpp> 
using boost::shared_ptr; 

#define _CRTDBG_MAP_ALLOC 
#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 

static struct myclass { 
    static shared_ptr<int> ptr; 

    myclass() { 
     ptr = shared_ptr<int>(NEW int); 
    } 
} myclass_instance; 

shared_ptr<int> myclass::ptr; 

int main() { 
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | 
        _CRTDBG_CHECK_ALWAYS_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); 
    return 0; 
} 
+0

爲什麼第二次調用參數或列表中的'_CrtSetDbgFlag()'? – sharptooth 2010-06-01 09:44:36

+0

這是將兩個語句合併爲一個的方法 – 2010-06-01 09:49:52

+0

我不明白。你爲什麼不「或」四個標誌,而是調用「或」列表中的函數? – sharptooth 2010-06-01 10:02:42

回答

8

在猜測的CRT報告的是假陽性 - 下面的代碼說明了共享指針是否正常工作,至少使用g ++

#include <iostream> 
#include "boost/shared_ptr.hpp" 
using namespace std; 
using namespace boost; 

struct R { 
    R() { 
     cerr << "ctor" << endl; 
    } 

    ~R() { 
     cerr << "dtor" << endl; 
    } 
}; 

struct A { 
    static shared_ptr<R> ptr; 

    A() { 
    ptr = shared_ptr<R>(new R); 
    } 

}; 

shared_ptr<R> A::ptr; 
static A a; 

int main() { 
} 

它打印:

ctor 
dtor 
+0

+1爲測試代碼 – neuro 2010-06-01 13:50:24

8

最有可能被檢測到泄漏的全局對象被摧毀和shared_ptr有機會釋放對象之前,所以它可能是泄漏。

11

這是內存泄漏。您正在初始化myclass的一個名爲myclass_instance的靜態實例。您還正在初始化「shared_ptr myclass :: ptr」。

根據Stroustrup [3],靜態按其定義的順序進行初始化。因此,你有myclass_instance的靜態定義,它初始化構造中的內部ptr。但是,您接下來定義了靜態myclass :: ptr,它調用了shared_ptr的默認構造函數。

這是一個典型的靜態排序問題的例子。編譯器認爲myclass :: ptr並未實際初始化,因此不會破壞原始的shared_ptr。相反,它只是泄露。

您將需要某種裸指針。如果您使用的是C++ 11,那麼您可以使用三態賦值語句來執行Nifty Counter Technique,如果您確定該對象已經被初始化,則它會自動移動到自身。這很粗糙,但它的工作原理。

這是我怎麼會做它在C++ 11:

#include <crtdbg.h> 
#include <memory> 
using std; 

#define _CRTDBG_MAP_ALLOC 
#define NEW new(_NORMAL_BLOCK, __FILE__, __LINE__) 

// Note that the count could also be a field in an initializer static used in the Nifty Counter 
// Technique covered in many texts. 
static int count = 0; // This gets implicitly initialized to 0 by the executable load into memory. 
static struct myclass { 
    static shared_ptr<int> ptr; 

    myclass() { 
     if (count++ == 0) { 
     ptr = make_shared<int>(0); //initialization 
     } 
    }   
} myclass_instance; 

shared_ptr<int> myclass::ptr = count == 0 ? make_shared<int>(0) : move(myclass::ptr); 

int main() { 
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | 
        _CRTDBG_CHECK_ALWAYS_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); 
    return 0; 
} 

更多信息請參閱以下內容:

  1. 洛科什,J,1996年,大規模的C++軟件設計。第7.8.1.3節, 艾迪生韋斯利,馬薩諸塞州雷丁市。
  2. Meyers,S,2005,Effective C++,Third Edition。項目4:確保對象在使用前初始化爲 。 Addison Wesley,馬薩諸塞州雷丁市。 Stroustrup,B,2000,C++編程語言特別版。 第10.4.9節,艾迪生韋斯利,馬薩諸塞州雷丁市。
+0

我認爲這是唯一正確的答案,由於A和A :: ptr的順序不同,因此anon的早期答案不是正確的轉錄。 – 2014-01-28 18:21:24