全局新操作符重载 [英] Global new operator overloading

查看:166
本文介绍了全局新操作符重载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已阅读 new 和 delete www.flipcode.com/archives/How_To_Find_Memory_Leaks.shtmlrel =nofollow> How_To_Find_Memory_Leaks

I have read about new and delete overloading for memory tracking in How_To_Find_Memory_Leaks

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

I defined these global operators:

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;
}

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

It works well with new and new[] operators, but i have a problem with placement new ( second one ). My define look like:

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

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

They work separately. But when i try to use them both there are errors appear. As I understand they substitute each other. I know I can have macro with variable number of arguments like this:

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

但是我需要同样的宏有和没有参数,所以两个 new -s在这些行中替换right:

But I need the same macro with and without arguments at all, so both new-s in these lines substitute right:

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


推荐答案

如果你决定走黑路,全局新,你必须确保你考虑所有以下场景:

If you decide to walk the dark path of overriding the global new, you have to make sure you consider all of the following scenarios:

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

并且应该可以处理所有上面除了最后一个。 Shudder。

And it should be possible to be able to handle all the above except for the last. Shudder.

必要的knol和手势是你的宏应该以 new / strong>。当你的宏以 new 结尾时,你可以委托不同的方式调用 new 本身。

The necessary knol and the sleight of hand is that your macro should end with new. When your macro ends with new, you can delegate the different ways it can be invoked to new itself.

这里有一个,非线程安全的方式继续。定义一个类型来捕获调用的上下文,所以我们稍后可以在运算符本身中检索这个上下文。

Here's one, non-thread safe way to proceed. Define a type to capture the context of the invocation, so we will be able to retrieve this context later in the operator itself,

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 临时就在调用之前,

Next, define your override to create a new_context temporary just before the invocation,

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

使用三元运算符条件赋值来计算表达式,这是我们上面定义的运算符bool 很方便的地方。

using the ternary operator conditional assignment to evaluate an expression before delegating to the operator new, notice that it is where the operator bool that we have defined above comes handy.

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

Then inside your new overrides (I'll use standard C++98 here instead of the MSC C++), all you have to do is to retrieve the context:

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;
}

此方法将处理所有情况 4 从上面,并且什么是重要的,可以很容易忽略是,如果 4 其中你的重载不被调用,因为你不能替换刊登位置新版(§18.4.1.3),您仍然知道刊登位置新讯息已发生,因为 new_context 将被建立并遭到破坏。

This approach will deal with all the cases 1-4 from above, and what's important and can be easily overlooked is that in case 4 where your overloads are not invoked, as you cannot replace placement new (§18.4.​1.3), you still know that placement new took place because new_context will be created and destroyed.

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

To summarise, you don’t need to modify what follows after the new operator, so all possible syntaxes remain valid. And the other point is that the new_context object temporary is going to be kept alive until the end of the expression the operator participates in, so you are safe to obtain it from a global singleton.

查看实际的gcc示例 适应MSC是留给读者。

这篇关于全局新操作符重载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆