全局新运算符重载

Global new operator overloading

本文关键字:重载 运算符 全局      更新时间:2023-10-16

我已经阅读了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;
}

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

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

它们分别工作。但当我尝试同时使用它们时,会出现错误。据我所知,他们互相替代。我知道我可以有一个具有可变参数数量的宏,如下所示:

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

但我需要相同的宏,有参数和没有参数,所以这两行中的new-都替换了right:

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

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

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

除了最后一个之外,应该可以处理以上所有内容。颤抖

必要的技巧是宏应该以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

使用三元运算符条件赋值来计算表达式,然后再将其委托给运算符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对象临时将保持活动状态,直到操作符参与的表达式结束,因此可以安全地从全局单例中获取它。


请参阅gcc示例适应MSC由读者决定