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
source to share
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, ...);
source to share
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.
source to share