全局新运算符重载

use*_*351 2 c++ operator-overloading new-operator

我在How_To_Find_Memory_Leaks中阅读了有关内存跟踪new和重载的内容delete

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

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;
}
Run Code Online (Sandbox Code Playgroud)

它与 new 和 new[] 运算符配合良好,但我在放置 new 时遇到问题(第二个)。我的定义如下:

#define new new( __FILE__, __LINE__)
#define new(x) new( x, __FILE__, __LINE__)
Run Code Online (Sandbox Code Playgroud)

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

#define new( ... ) new( __VA_ARGS__, __FILE__, __LINE__)
Run Code Online (Sandbox Code Playgroud)

但我需要带有和不带有参数的相同宏,因此new这些行中的两个 -s 都替换为正确的:

g_brushes = new Brush[ num_brushes ];
...
new( &g_brushes[i] )Brush(sides);
Run Code Online (Sandbox Code Playgroud)

moc*_*ace 5

如果您决定走上推翻全球新事物的黑暗道路,您必须确保考虑以下所有场景:

\n\n
new Foo;                            // 1\nnew Foo[10];                        // 2\nnew (std::nothrow) Foo;             // 3\nnew (p) Foo;                        // 4 - placement, not overridable\n(Foo*) ::operator new(sizeof(Foo)); // 5 - direct invocation of the operator\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且应该能够处理除最后一个之外的所有上述问题。不寒而栗。

\n\n

必要的技巧和技巧是你的宏应该以 结尾new。当宏以 结尾时new,您可以将调用它的不同方式委托给new自身。

\n\n

这是一种非线程安全的方法。定义一个类型来捕获调用的上下文,因此我们稍后将能够在运算符本身中检索此上下文,

\n\n
struct new_context {\n    new_context(const char* file, const int line)\n        : file_(file), line_(line) { scope_ = this; }\n    ~new_context() { scope_ = 0; }\n\n    static new_context const& scope() { assert(scope_); return *scope_; }\n\n    operator bool() const { return false; }\n\n    const char* file_;\n    const int line_;\nprivate:\n    static new_context* scope_;\n};\n
Run Code Online (Sandbox Code Playgroud)\n\n

new_context接下来,定义您的覆盖以在调用之前创建一个临时文件,

\n\n
#define new new_context(__FILE__, __LINE__) ? 0 : new\n
Run Code Online (Sandbox Code Playgroud)\n\n

在委托给运算符 new 之前使用三元运算符条件赋值来计算表达式,请注意,这是operator bool我们上面定义的 派上用场的地方。

\n\n

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

\n\n
void* operator new (std::size_t size) throw (std::bad_alloc) {\n    std::cout \n        << "new" \n        << "," << new_context::scope().file_ \n        << ":" << new_context::scope().line_ \n        << std::endl;\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种方法将处理上面的所有情况1-4,重要且容易被忽视的是,如果4您的重载未被调用,因为您无法替换新的位置(\xc2\xa718.4.\xe2\ x80\x8b1.3),您仍然知道放置 new 发生了,因为new_context将被创建和销毁。

\n\n
\n\n

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

\n\n
\n\n

请参阅现场的 gcc 示例适应 MSC 留给读者。

\n