首页 文章

Boost池分配器不能用g中的std :: allocate_shared编译

提问于
浏览
9

编辑:

澄清我期望的结果,因为我没有很好地传达它:
能够使用 std::allocate_sharedboost::fast_pool_allocator 作为分配方法,使用g 4.8或更高版本,使用boost 1.56.0 . 目前这适用于g 4.6,并且在4.7,4.8和4.9上失败 .

要明确的是,我不打算为g 4.7做这项工作 .

测试代码产生错误:

#include "boost/pool/pool.hpp"
#include "boost/pool/pool_alloc.hpp"

#include <memory>

int main(int argc, char** argv)
{
  auto fails = std::allocate_shared<int>( boost::fast_pool_allocator<int>() );

  auto works = std::allocate_shared<int>(boost::fast_pool_allocator<int>(), 5);
}

在我们的代码库中,我们将std :: allocate_shared与boost池分配器结合使用,这会导致一些讨厌的编译错误 . 然而,这已经在不同版本的g中变形和变化:
详情:64bit,(4.7,4.8)-std = c 11,(4.6)-std = c 0x,boost 1.56.0
4.6 - 愉快地编译
4.7 - 崩溃编译器

内部编译器错误:重新输入错误报告例程 . 如果合适,请提交完整的错误报告,并提供预处理的来源 . 请参阅说明 . 存储在/tmp/cca0Emq9.out文件中的预处理源,请将其附加到您的bug报告中 .

4.8 - 令人讨厌的编译错误

/XXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399:
错误:使用已删除的函数'std :: _ Sp_counted_ptr_inplace,(__ gn_cxx :: _ Lock_policy)2u> :: _ Sp_counted_ptr_inplace(const std :: _ Sp_counted_ptr_inplace,(__ gn_cxx :: _ Lock_policy)2u>&)'{new(ptr)T(t) ; } ^ / usr / include / c /4.8/bits/shared_ptr_base.h:198:错误:'std :: _ Sp_counted_base <_Lp> :: _ Sp_counted_base(const std :: _ Sp_counted_base <_Lp>&)[与__gnu_cxx :: _ Lock_policy Lp =(_ nuu_cxx :: _ Lock_policy)2u]'是私有的_Sp_counted_base(_Sp_counted_base const&)= delete; ^ / usr / include / c /4.8/bits/shared_ptr_base.h:379:错误:在此上下文类_Sp_counted_ptr_inplace final:public _Sp_counted_base <_Lp> ^ / usr / include / c /4.8/bits/shared_ptr_base.h:379:错误:使用已删除的函数'std :: _ Sp_counted_base <_Lp> :: _ Sp_counted_base(const std :: _ Sp_counted_base <_Lp>&)[与__gnu_cxx :: _ Lock_policy Lp =(_ nuu_cxx :: _ Lock_policy)2u]'/ usr / include / c /4.8/bits/shared_ptr_base.h:198:错误:此处声明_Sp_counted_base(_Sp_counted_base const&)= delete; ^

4.9 - 令人讨厌的编译错误(略有不同)

/XXXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399:错误:使用已删除的函数'std :: _ Sp_counted_ptr_inplace,(__ gn_cxx :: _ Lock_policy)2u> :: _ Sp_counted_ptr_inplace(const std :: _ Sp_counted_ptr_inplace,(__ nuu_cxx ::) _Lock_policy)2u>&)'{new(ptr)T(t); } ^ / usr / include / c /4.9/bits/shared_ptr_base.h:203:错误:'std :: _ Sp_counted_base <_Lp> :: _ Sp_counted_base(const std :: _ Sp_counted_base <_Lp>&)[与__gnu_cxx :: _ Lock_policy Lp =(_ nuu_cxx :: _ Lock_policy)2u]'是私有的_Sp_counted_base(_Sp_counted_base const&)= delete; ^ / usr / include / c /4.9/bits/shared_ptr_base.h:494:错误:在此上下文类_Sp_counted_ptr_inplace final:public _Sp_counted_base <_Lp> ^ / usr / include / c /4.9/bits/shared_ptr_base.h:494:错误:使用已删除的函数'std :: _ Sp_counted_base <_Lp> :: _ Sp_counted_base(const std :: _ Sp_counted_base <_Lp>&)[与__gnu_cxx :: _ Lock_policy Lp =(_ nuu_cxx :: _ Lock_policy)2u]'

我花了很多时间试图深入研究这个问题,如果有人更熟悉这些组件的内部工作原理,我会感激不尽 .

2 回答

  • 3

    我花了很多时间查看不同的编译器版本,假设这是一个编译器错误,如g 4.7中的崩溃和其他回答者/评论者的评论所示 . 然而,在回到编译错误并挖掘它们一段时间之后,我设法最终以一定程度的特异性理解编译错误的原因 .

    所以问题确实存在于 boost::fast_pool_allocatorboost::pool_allocator 中,回想起来似乎有点明显 . 问题的基本症结在于,boost allocators construct method是根据c 98标准分配器规范实现的,并且有一个构造方法,该方法采用单个const&param来复制构造new的对象 . c 11样式使用可变参数模板,并且args被传递给通过placement new创建的对象的构造函数 . 在我的测试代码的特定情况下,它是不会将初始化值传递给导致错误的 std::allocate_shared 的变体 . 手头的核心问题是c 11 std::allocate_shared 试图将可变数量的参数传递给只需要一个的 construct() 方法 . 在我的测试中,当传入一个值并且没有为其他值调用时,我可以断开构造方法变种 . 例如,如果要分配 std::pair<> (2参数),则根本不调用构造方法,并且必须使用其他一些机制 . 我跟踪了一下这看起来像 std::allocate_shared 在内部包装了构造调用,如果对构造的调用不匹配,则调用另一个方法(通过隐式函数查找)直接构造对象 . 下面的top方法调用分配器的 construct() 方法,底层的新方法直接调用对象:

    alloc_traits.h:250-61

    template<typename _Tp, typename... _Args>
    static typename
        enable_if<__construct_helper<_Tp, _Args...>::value, void>::type
        _S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args)
    { __a.construct(__p, std::forward<_Args>(__args)...); }
    
    template<typename _Tp, typename... _Args>
    static typename
    enable_if<__and_<__not_<__construct_helper<_Tp, _Args...>>,
             is_constructible<_Tp, _Args...>>::value, void>::type
        _S_construct(_Alloc&, _Tp* __p, _Args&&... __args)
    { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); }
    

    这是我有时间去确定编译错误的来源,但这足以让我为这个问题整理一个简单而有效的解决方案 .

    这里的解决方案很简单;需要更新boost以使用新的c 11分配器规范 . 这样做实际上非常简单;在pool_alloc.hpp中替换所有实例:

    void construct(const pointer ptr, const value_type & t)
    { new (ptr) T(t); }
    

    template <typename... Args>
    void construct(const pointer ptr, Args&&... args)
    {
      new (ptr) T( std::forward<Args>(args)... );
    }
    

    似乎这是一个错误,提升没有更新他们的代码以获得c 11支持,但事实上g 5.0(我确认)编译没有问题意味着添加此支持不是强制性的 . 可能是 std::allocate_shared 旨在向后兼容旧的分配器接口,4.7,4.8和4.9的崩溃和编译错误是支持被破坏 . 我将在增强错误跟踪器上发布一张票,看看他们认为这笔交易是什么:boost trac ticket

  • 2

    由于这似乎是libstdc的一个问题(?),你可以使用标准库函数的boost等效而不是boost::allocate_shared . 包括 <boost/make_shared.hpp> . 这是一个 Coliru demo ,显示四个不同的GCC版本编译正常 . 正如我在评论中提到的, std::allocate_shared 适用于GCC的主干版本和libc . 我无法找到与此问题相关的现有错误报告,但您可以为GCCBoost提交一个 .

相关问题