在OSX上替换libstdc ++。dylib(4.0)全局new和delete运算符

时间:2010-08-12 21:04:15

标签: c++ xcode gcc stl new-operator

我正在努力用XCode 3.2,GCC 4.2,libstdc ++ 4.0,动态版本替换全局new和delete运算符。

我直接从标题“new”中获取了原型并实现了它们。它们贴在下面。

该项目是一个.plugin,因此是一个动态的lib。这个插件必须将分配委托给主应用程序自己的alloc / free例程,这些例程位于旧的C ++中。

我自己调用new / delete以及std :: list和std :: map分配都被正确替换,但是当std :: vector :: push_back不得不增长缓冲区时。在这种情况下,我的操作员new没有被调用但是我的操作符删除是。我知道,因为我在我的新运算符分配的任何缓冲区的前四个字节中写了一个标记,我在operator delete中检查了这个标记。请参阅下面的违规代码。

extern "C++"
{
__attribute__((visibility("default"))) void* operator new(std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void* operator new[](std::size_t) throw (std::bad_alloc);
__attribute__((visibility("default"))) void operator delete(void*) throw();
__attribute__((visibility("default"))) void operator delete[](void*) throw();
__attribute__((visibility("default"))) void* operator new(std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void* operator new[](std::size_t, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete(void*, const std::nothrow_t&) throw();
__attribute__((visibility("default"))) void operator delete[](void*, const std::nothrow_t&) throw();

}

当“yo”超出范围时,以下代码将导致断言,因为为我的运算符new分配了为std :: vector分配的内存。

   {
        std::vector<std::string> yo;
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

以下代码没问题,因为std :: vector :: reserve会调用我的operator new:

   {
        std::vector<std::string> yo;
        yo.reserve(4);
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
        yo.push_back("yoyoma");
    }

当需要增长缓冲区(该方法名为_M_insert_aux)时,GBD(调试器)不会让步骤进入std :: vector :: push_back实现。我所知道的是,我的operator new永远不会从std :: vector :: push_back调用。

上面的解决方法无法应用于我正在使用的所有第三方库。其中一个是push_back的大用户。

我尝试静态链接到libstdc ++。但是我遇到了同样的问题。

是否有一些std :: vector&lt;的特化std :: string&gt;不使用全局新运算符?

顺便说一句,这在VS9的Windows上完美运行。

4 个答案:

答案 0 :(得分:1)

我终于通过使用George Costanza的技术解决了我的问题:做相反的事情。

我没有试图让我的操作符成为新的并删除可见的内容,而是完全隐藏了它们。

诀窍是在每个静态库中设置它们。在捆绑设置中:

  • 设置C ++标准库类型:静态
  • 默认隐藏的符号:已选中
  • 修复&amp;继续:未选中(非常重要,否则将默默禁用以前的设置)

并做一个干净的所有&amp;构建,因为使用XCode 3.2只需在更改这些设置后点击Build就不起作用。

显然,我更换了操作员new&amp;删除原型:

#pragma GCC visibility push(hidden)

extern "C++"
{
    void* operator new(std::size_t) throw (std::bad_alloc);
    void* operator new[](std::size_t) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void operator delete[](void*) throw();
    void* operator new(std::size_t, const std::nothrow_t&) throw();
    void* operator new[](std::size_t, const std::nothrow_t&) throw();
    void operator delete(void*, const std::nothrow_t&) throw();
    void operator delete[](void*, const std::nothrow_t&) throw();
} // extern "C++"

#pragma GCC visibility pop

不,为什么这样做?必须同时具有静态+隐藏符号才能工作。它似乎保护我的bundle插件免受内联其分配器的STL特化实现的影响。

另请注意,这只发生在从大型应用动态加载的捆绑插件中。在从控制台应用程序调用的一个简单的.dylib项目中,任何设置都可以正常工作。

答案 1 :(得分:0)

我不确定如何完全按照您的要求进行操作,但您可以使用自定义分配器在STL中实现自己的分配语义。

http://www.cplusplus.com/reference/std/memory/allocator/

我想我记得当我看到Hans-Bohen GC for C ++时,库会用GC版本替换new / delete但是你仍然必须将一个分配器传递给你想要使用的STL结构。

此外,您使用的库中可能仍有使用malloc的代码。需要考虑的事情。

答案 2 :(得分:0)

_M_insert_aux位于vector.tcc,这对GCC来说并不合适。但是,快速扫描显示它就像其他方法一样正确调用分配器。

  pointer __new_start(this->_M_allocate(__len));

您可以尝试在operator new中设置断点,定义一个自定义分配器(您可以从std::allocator派生)打印调试输出,或在new_allocator.h:91中设置断点应该调用你的覆盖。

答案 3 :(得分:0)

最可能的解释是GCC的std :: vector的内部实现包括new的额外重载。 MSVC有许多额外的操作员新过载。您需要拆分源代码或制作新的自定义分配器。