【问题标题】:Global overload delete[] not called in third-party libraries第三方库中未调用全局重载 delete[]
【发布时间】:2014-10-25 03:22:33
【问题描述】:

我正在尝试了解C++ 中的内存池,以获得更好的速度和调试功能。我一直在遵循这里找到的方法:http://oroboro.com/overloading-operator-new/。所以我像这样重载了newnew[]deletedelete[]

inline void* operator new     ( size_t size ) { return myAlloc( size ); }
inline void* operator new[]   ( size_t size ) { return myAlloc( size ); }
inline void  operator delete  ( void* ptr   ) { myFree( ptr ); }
inline void  operator delete[]( void* ptr   ) { myFree( ptr ); }

我喜欢第三方库被定向到这个版本的new,但是我遇到了一个问题。我正在制作一个使用 DXUT 的DirectX 应用程序。我将 DXUT 与我的项目分开编译。最终它会调用:

std::unique_ptr<D3D11_SUBRESOURCE_DATA[]> initData( new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] );

一旦这个唯一指针超出范围,它就会在调用delete[] _Ptr 时崩溃,这并没有通过我的重载运算符。我尝试通过在我的main 中添加int* dummy = new int[10]; delete[] dummy; 来调试我的内存池实现。构建项目时出错,但清理构建工作正常。令我惊讶的是,一切正常,包括崩溃的 DXUT 线路!

问题 1:当我添加修复问题的调试行时究竟发生了什么?我猜出于某种原因,直到我在自己的应用程序代码中调用它之前,我的操作符 delete[] 才知道?这能保证解决问题还是只是运气不好?

问题2:我注意到new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ]并没有直接调用我的operator new[],而是最终调用了我的operator new(没有括号)。它仍然在指针上调用运算符delete[]。这会造成问题吗?我是否必须添加适当的重载才能调用我的 operator new[] 或者这种行为是否正常?

作为参考,被调用的 operator new[] 重载是:

void * __CRTDECL operator new[](::size_t count, const std::nothrow_t& x)
_THROW0()
{ // Try to allocate count bytes for an array
    return (operator new(count, x));
}

【问题讨论】:

    标签: c++ memory-management


    【解决方案1】:

    问题 1:当我添加调试行时到底发生了什么 解决了这个问题?我猜出于某种原因我的操作员 delete[] 不是 直到我在自己的应用程序代码中调用它才知道?这有保证吗 解决问题还是只是运气不好?

    §3.2 [basic.def.odr]/p4:

    应在每个翻译单元中定义内联函数 它是 odr 使用的。

    听起来你的编译器没有为全局 operator delete[] 生成代码,因为它没有在你的主翻译单元中使用并且被标记为 inline(这意味着编译器可以假设任何使用它们的翻译单元都会有它们的定义)。但是,您单独编译的库没有这些函数的定义,您最终会使用标准库中的默认函数。将它们设为非inline 应该可以解决问题。

    问题 2:我注意到 new (std::nothrow) D3D11_SUBRESOURCE_DATA[ mipCount * arraySize ] 没有给我打电话 直接operator new[],但最终打电话给我的operator new(没有 括号)。它仍然在指针上调用运算符delete[]。做 这有什么问题吗?我是否必须添加适当的重载,例如 我的operator new[] 被调用还是这种行为正常?

    operator new [] 的抛出和非抛出版本的默认版本,以及operator new 的非抛出版本,都指定调用 operator new 的抛出版本来获取内存。所以你在那里是安全的。但是,您的operator new 的定义可能是错误的。它们必须返回有效指针或抛出异常。不允许返回空指针。

    【讨论】:

    • 删除内联代码并将代码放在实现文件中而不是头文件中!我想知道为什么我复制的链接没有提及它。
    猜你喜欢
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-25
    • 1970-01-01
    相关资源
    最近更新 更多