重载新的操作员问题

时间:2011-07-22 10:07:30

标签: c++ memory new-operator memory-leaks operator-keyword

我决定在我的类中重载new,new [],...运算符,这样我就可以记录它们被调用的文件和行,这样我就可以更轻松地跟踪内存分配/泄漏。

现在问题出现在我的堆栈和数组类(以及分配内存的其他模板容器类)中:

如果我将它们与我的一个具有new,new [],...运算符的类一起使用它可以正常工作。

但是如果我将它与标准的c ++数据类型(int,float,...)一起使用,我就无法分配它们,因为没有重载的new运算符匹配new的参数(__ LINE __,__ FILE __)运营商(或其他类似新职位)。

堆栈代码示例:

// placement new
T* t=new(__ LINE __ , __ FILE__)(&m_data[i])T;

所以我对如何使这项工作有好主意。如果我用新的松散内存记录功能替换new(__ LINE __,__ FILE __)。 一种解决方案是为标准数据类型创建一个分离的堆栈,其中使用了默认的new。

有没有办法在编译时检测模板参数是结构,类还是内置的c ++类型?

你如何处理这样的事情? 你有什么建议? 对这种设计的任何评论(好的,坏的)显然都是受欢迎的(只是不要张贴诸如“不要用自己的容器重新发明轮子”这样的东西。)

3 个答案:

答案 0 :(得分:1)

请注意,您当前的解决方案需要将日志记录代码添加到您拥有的每个 new(line, file)超载。此外,除非您在#ifndef DEBUG ... #endif内包围每个日志记录调用,否则无法在发布版本中轻松将其关闭。

这是实现目标的一种方法:不要为每个类重载new运算符,而应考虑使用放置语法重载全局new运算符;这样你就可以避免干扰'普通'new运算符。然后,您可以#define新增和删除宏以方便使用,最重要的是,您可以控制何时应用内存跟踪new/delete以及何时使用标准版本。

#ifdef ENABLE_CUSTOM_ALLOC

// Custom new operator. Do your memory logging here.
void* operator new (size_t size, char* file, unsigned int line)
{
    void* x = malloc(size);
    cout << "Allocated " << size << " byte(s) at address " << x 
        << " in " << file << ":" << line << endl;
    return x;  
}

// You must override the default delete operator to detect all deallocations
void operator delete (void* p)
{
   free(p);
   cout << "Freed memory at address " << p << endl;
}

// You also should provide an overload with the same arguments as your
// placement new. This would be called in case the constructor of the 
// created object would throw.
void operator delete (void* p, char* file, unsigned int line)
{
   free(p);
   cout << "Freed memory at address " << p << endl;
}

#define new new(__FILE__, __LINE__)

#endif


// A test class with constructors and destructor
class X
{
public: 
    X() { cout << "X::ctor()" << endl; }
    X(int x) { cout << "X::ctor(" << x << ")" << endl; }
    ~X() { cout << "X::dtor()" << endl; }
};


int main (int argc, char* argv[])
{
    X* x3 = new X();
    X* x4 = new X(20);
    delete x3;
    delete x4;
}
你应该看到类似的东西:

Allocated 1 byte(s) at address 00345008 in Alloc.cpp:58
X::ctor()
Allocated 1 byte(s) at address 003450B0 in Alloc.cpp:59
X::ctor(20)
X::dtor()
Freed memory at address 00345008
X::dtor()
Freed memory at address 003450B0

尝试用X代替int,你会发现它也有效。您可以将此扩展到数组和放置新的,但我宁愿不使帖子比它更长。

最后几点指示:
- MSVC具有此功能,请参阅here
- 在“跟踪内存泄漏”部分下以here方式进行内存跟踪是一件很有意思的事情

答案 1 :(得分:0)

struct Int {
    int i;
    Int (int _i) : i(_i) {}
    operator int () const {return i;}
};

#define __LINE_NUMBER__ Int(__LINE__)

使用此宏代替标准行号宏,重载分辨率会将Int行号与int其他数字区分开来。

我无法想象这将如何全面发挥作用。你打算像int * x = NEW(int,123);那样使用它吗?

顺便说一句,我同意评论者的意见 - 你可能不必走这条路。重载new是一种黑色艺术,通常应该避免。

答案 2 :(得分:0)

  

有没有办法在编译时检测模板参数是结构,类还是   内置的c ++类型?

你可以使用boos :: type_traits和boost :: mpl。

示例:

#include <boost/type_traits.hpp>
#include <boost/mpl/not.hpp>
#include <boost/mpl/logical.hpp>

template <class T>
typename boost::enable_if<boost::is_class<T>, T>::type
foo(){cout << "is class " << endl;};

template <class T>
typename boost::enable_if<boost::mpl::not_<boost::is_class<T> >, T>::type
foo(){cout << "is not class "<< endl;};

类型列表 - http://www.boost.org/doc/libs/1_47_0/libs/type_traits/doc/html/index.html

或者您可以将boost :: mpl :: set用于您的类型集