2014-09-20 49 views
3

make_shared我代替new使用宏來獲得在調試模式下一些額外的信息:C++的std ::有新的宏

#if defined(_DEBUG) 
#define SAGE_NEW new(__FUNCTION__, __FILE__, __LINE__) 
#else 
#define SAGE_NEW new 
#endif 

我發現這個定製內存分析和內存泄漏檢測非常有用。我剛開始使用共享指針,所以現在我喜歡做堆對象:

auto myThingy = std::shared_ptr<Thingy>(SAGE_NEW Thingy(Args)); 

我剛纔得知std::make_shared是首選,因爲它使用較少的內存分配。有沒有什麼辦法可以將我的SAGE_NEW加入make_shared?我意識到這對泄漏檢測無關緊要,但我仍然喜歡它的內存使用情況統計。似乎allocate_shared以某種方式持有答案,但我還沒有弄清楚。謝謝! :)

編輯: 對那些詢問new - 我有一個自定義new超載了。編譯器選項SAGE_MEM_INFO將啓用泄漏檢測和內存使用統計信息,否則會跳過日誌記錄並直接進入我的內存池分配。我有新的[]和delete []變種,但我忽略那些爲簡潔:

#ifdef SAGE_MEM_INFO 
void* operator new (size_t size){ ++appAllocs; return myAlloc(size); } 
void* operator new (size_t size, char const *function, char const *filename, int lineNum) 
{ 
    ... Log memory usage 
    void* ptr = ::operator new(size); 
    return ptr; 
} 
void operator delete (void* ptr) 
{ 
    ... Log freeing of this pointer 
    --appAllocs; 
    myFree(ptr); 
} 
void operator delete (void* ptr, char const *function, char const *filename, int lineNum) 
{ 
    ... Log freeing of this pointer 
    --appAllocs; 
    myFree(ptr); 
} 
#else 
void* operator new (size_t size){ return myAlloc(size); } 
void* operator new (size_t size, char const *function, char const *filename, int lineNum) 
{ 
    void* ptr = ::operator new(size); 
    return ptr; 
} 
void operator delete (void* ptr) { myFree(ptr); } 
void operator delete (void* ptr, char const *function, char const *filename, int lineNum) { myFree(ptr); } 
#endif 
+0

快速評論:人們經常提到make_shared的內存分配。這是真的,但這是一次性成本(每個指針)。另一個很好的理由是,當你使用make_shared時,對象本身及其引用計數(可能還有其他東西)全部被放入連續的內存塊中。這會導致複製和刪除副本的更好的緩存行爲,這種操作可能會在創建的每個指針上重複多次。 – 2014-09-20 18:51:54

+0

如果您有解決方案,請將其寫爲答案。這個問題的答案是,你的_問題。 – 2014-09-20 22:38:05

+0

對於上面顯示的原始宏,您需要記住定義一個相應的佈局「operator delete」,因爲如果構造函數拋出,則由佈局新表達式調用該佈局。沒有它,你會得到內存泄漏,這是你要消除的東西。這是一次臭名昭着的MFC錯誤。 – 2014-09-20 22:54:25

回答

1

是的,你當然可以這樣做。

不過,你必須選擇你的毒藥:

  • 使用分配器型是不是空的,但節省了至少一個指針。
  • 爲每個分配使用一個新的分配器類型,這將反映在引用計數的新多態類型中。

http://en.cppreference.com/w/cpp/concept/Allocator顯示了需求和一個很好的最小分配器聲明。

改編std::allocator這裏的第一個選項:

#if defined(_DEBUG) 
template <class Tp> 
struct DebugLinesAllocator : std::allocator<Tp> { 
    const char* func, *file; 
    int line; 
    Tp* allocate(std::size_t n, const void* = 0) 
    {return ::operator new(n * sizeof(T), func, file, line);} 
    template< class U > struct rebind { typedef DebugLinesAllocator<U> other; }; 
    DebugLinesAllocator(const char* func, const char* file, int line) 
    : func(func), file(file), line(line) {} 
    template< class U > DebugLinesAllocator(const DebugLinesAllocator<U>& other) 
    : func(other->func), file(other->file), line(other->line) {} 
}; 
#define SAGE_MAKE_SHARED(type, ...) allocate_shared<type>(DebugLinesAllocator<type>\ 
    {__FUNCTION__, __FILE__, __LINE__}, __VA_ARGS__) 
#else 
#define SAGE_MAKE_SHARED(type, ...) make_shared<type>(__VA_ARGS__) 
#endif 

儘管如此,它遠不如共享三分球是有用的。無論如何,每一點點都可能有所幫助。

使用它像答案,而不是問題

auto p = SAGE_MAKE_SHARED(my_type, my_argument_1, ...); 
+0

在C++ 11中不需要'rebind'。 – Puppy 2014-09-20 18:21:32

+0

@Puppy:儘管如此,基地級可能有它,所以我最好也是。 (可能還記得那個時候我不會添加到'std :: allocator') – Deduplicator 2014-09-20 18:24:10

+0

謝謝。似乎工作,但我添加了一個static_cast,明確寫了__FUNCTION__的類型,等等。請參閱我編輯的答案。再次感謝! – DSM 2014-09-20 22:29:13

0

您可以創建自己的makeShared在那裏你會做任何你需要的簿記和事後你會調用真正的make_shared

0

發佈...

我的編譯器不喜歡在Deduplicator的回答一些事情。下面似乎並沒有完全錯誤:

template <class Tp> 
struct DebugLinesAllocator : std::allocator<Tp> { 
    char const * func; 
    char const * file; 
    int line; 
    DebugLinesAllocator(char const * aFunc, char const * aFile, const int aLine) : func(aFunc), file(aFile), line(aLine) {} 
    Tp* allocate(std::size_t n, const void* = 0) 
    { 
     return static_cast<Tp*> (::operator new(n * sizeof(Tp), func, file, line)); 
    } 
    template< class U > struct rebind { typedef DebugLinesAllocator<U> other; }; 
    template< class U > DebugLinesAllocator(const DebugLinesAllocator<U>& other) 
     : func(other.func), file(other.file), line(other.line) {} 
}; 
#if defined(_DEBUG) 
#define SAGE_MAKE_SHARED(type, ...) std::allocate_shared<type>(DebugLinesAllocator<type>(__FUNCTION__, __FILE__, __LINE__), __VA_ARGS__) 
#else 
#define SAGE_MAKE_SHARED(type, ...) std::make_shared<type>(__VA_ARGS__) 
#endif 

請讓我知道如果你認爲我的任何變化是可疑的。