3

我使用宏代替new在调试模式下获取一些额外信息:

#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_NEWmake_shared吗?我意识到泄漏检测并不重要,但我仍然希望它用于内存使用统计。似乎allocate_shared以某种方式掌握了答案,但我还没有弄清楚。谢谢!:)

编辑:对于那些询问new-我用自定义重载它new。编译器选项 SAGE_MEM_INFO 打开泄漏检测和内存使用统计信息,否则它会跳过日志记录并直接进入我的内存池分配。我有 new[] 和 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
4

3 回答 3

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, ...);
于 2014-09-20T14:21:39.447 回答
0

您可以创建自己的makeShared,您将在其中进行所需的任何簿记,然后您将调用 real make_shared

于 2014-09-20T14:07:46.110 回答
0

Posting in answers rather than the question...

My compiler didn't like some things in Deduplicator's answer. Below doesn't seem to be completely wrong:

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

Please let me know if you think any of my changes are suspect.

于 2014-09-21T14:06:00.487 回答