C ++ std :: make_shared with new macro

I use a macro instead new

to get more information in debug mode:

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

      

I found this very useful in custom memory profiling and memory leak detection. I just started using shared pointers, so now I am creating heap objects like:

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

      

I just found out which std::make_shared

is preferred as it uses fewer memory allocations. Is there a way to include mine SAGE_NEW

in make_shared

? I understand that it doesn't matter for leak detection, but I would still like the memory usage statistics. It seems to allocate_shared

hold the answer somehow, but I didn't get it. Thank you! :)

Edit : For those asking about new

, I am overloading it with new

. The SAGE_MEM_INFO compiler option enables leak detection and memory usage statistics, otherwise it skips the logging and goes directly to the memory pool allocation. I have new [] and delete [] options, but I omit them for brevity:

#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

      

+3


source to share


3 answers


Yes, you can do it.

However, you need to choose your poison:

  • Use an allocator type that is not empty but retains at least a pointer.
  • Use a new allocator type for each allocation, which will appear in a new polymorphic type for the reference account.

http://en.cppreference.com/w/cpp/concept/Allocator shows requirements and a nice minimum allocator declaration.

Adapted std::allocator

here for the first option:



#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

      

However, this is much less useful for general pointers. Anyway, every bit can help.

Use it like

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

      

+1


source


You can create your own makeShared

, where you will do all the bookkeeping you need and then you call the real one make_shared

.



0


source


Posting answers, not a question ...

My compiler didn't like Deduplicator. Below doesn't seem to be entirely 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.

0


source







All Articles