全局新运营商重载

时间:2014-02-23 19:49:24

标签: c++ operator-overloading new-operator

我已阅读How_To_Find_Memory_Leaks

中有关newdelete内存跟踪重载的内容

我定义了这些全局运算符:

inline void* __cdecl operator new( unsigned int size, const char *file, int line ) {
    void* ptr = malloc( size );
    AddTrack((DWORD)ptr, size, file, line);
    return ptr;

}

inline void* __cdecl operator new( unsigned int size, void* ptr, const char *file, int line ) {
    return ptr;
}

它适用于新的和新的[]运算符,但我有一个新的放置(第二个)的问题。我的定义看起来像:

#define new new( __FILE__, __LINE__)
#define new(x) new( x, __FILE__, __LINE__)

他们分开工作。但是当我尝试使用它们时,都会出现错误。据我所知,他们互相替代。我知道我可以使用像这样可变数量的参数的宏:

#define new( ... ) new( __VA_ARGS__, __FILE__, __LINE__)

但是我需要有和没有参数的相同的宏,所以这些行中的new - s替换为右:

g_brushes = new Brush[ num_brushes ];
...
new( &g_brushes[i] )Brush(sides);

1 个答案:

答案 0 :(得分:4)

如果你决定走上覆盖全球新道路的黑暗道路,你必须确保考虑以下所有场景:

new Foo;                            // 1
new Foo[10];                        // 2
new (std::nothrow) Foo;             // 3
new (p) Foo;                        // 4 - placement, not overridable
(Foo*) ::operator new(sizeof(Foo)); // 5 - direct invocation of the operator

应该可以处理除上一个之外的所有上述内容。颤动。

必要的knol和手法是你的宏应以new 结尾。当您的宏以new结尾时,您可以将调用它的不同方式委托给new本身。

这是一种非线程安全的方法。定义一个类型来捕获调用的上下文,这样我们以后就可以在运算符本身中检索这个上下文,

struct new_context {
    new_context(const char* file, const int line)
        : file_(file), line_(line) { scope_ = this; }
    ~new_context() { scope_ = 0; }

    static new_context const& scope() { assert(scope_); return *scope_; }

    operator bool() const { return false; }

    const char* file_;
    const int line_;
private:
    static new_context* scope_;
};

接下来,定义覆盖以在调用之前创建new_context临时

#define new new_context(__FILE__, __LINE__) ? 0 : new

使用三元运算符条件赋值在委托给operator new之前计算表达式,注意它是我们在上面定义的operator bool得到的便利。

然后在你的新覆盖内(我将在这里使用标准C ++ 98而不是MSC C ++),你所要做的就是检索上下文:

void* operator new (std::size_t size) throw (std::bad_alloc) {
    std::cout 
        << "new" 
        << "," << new_context::scope().file_ 
        << ":" << new_context::scope().line_ 
        << std::endl;
    return 0;
}

这种方法将处理上面的所有案例1-4,重要且容易被忽视的是4未调用重载的情况,因为无法替换放置新的(§18.4.1.3),您仍然知道新的展示位置是因为new_context将被创建和销毁。


总而言之,您无需修改​​new运算符后面的内容,因此所有可能的语法仍然有效。另一点是new_context对象临时将保持活动直到操作员参与的表达式结束,因此您可以安全地从全局单例中获取它。


<强> See a gcc example live 即可。 适应MSC留给读者。