Boost池分配器不会使用g ++中的std :: allocate_shared进行编译

rad*_*man 9 c++ boost compiler-errors g++ c++11

编辑:

澄清我想要的结果,因为我还没有沟通得好:
为了能够使用std::allocate_sharedboost::fast_pool_allocator作为使用G ++ 4.8或更高升压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);
}
Run Code Online (Sandbox Code Playgroud)

在我们的代码库中,我们将std :: allocate_shared与boost池分配器结合使用,这会导致一些讨厌的编译错误.然而,这已经在不同版本的g ++中变形和变化:
细节:64位,(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:
Run Code Online (Sandbox Code Playgroud)

错误:使用删除功能 '的std :: _ Sp_counted_ptr_inplace,(__gnu_cxx :: _ Lock_policy)2U> :: _ Sp_counted_ptr_inplace(常量性病:: _ Sp_counted_ptr_inplace,(__gnu_cxx :: _ Lock_policy)2U>&)' 的{新(PTR)T(t)的; } ^

/usr/include/c++/4.8/bits/shared_ptr_base.h:198:错误:"的std :: _ Sp_counted_base <_Lp> :: _ Sp_counted_base(常量性病:: _ Sp_counted_base <_Lp>&)与__gnu_cxx :: _ Lock_policy _Lp =( __gnu_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(常量性病:: _ 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:错误:使用删除功能的"标准:: _ Sp_counted_ptr_inplace,(__gnu_cxx :: _ Lock_policy)2U> :: _ Sp_counted_ptr_inplace(常量性病:: _ Sp_counted_ptr_inplace,(__gnu_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(常量性病:: _ Sp_counted_base <_Lp>&)与__gnu_cxx :: _ Lock_policy _Lp =( __gnu_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(常量性病:: _ Sp_counted_base <_Lp>&)与__gnu_cxx :: _Lock_policy _Lp =(__ nuu_cxx :: _ Lock_policy)2u]'

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

rad*_*man 3

我花了很多时间查看不同的编译器版本,假设这是一个编译器错误,正如 g++4.7 中的崩溃和其他回答者/评论者的评论所暗示的那样。然而,在回到编译错误并深入研究它们一段时间后,我终于在一定程度上了解了编译错误的原因。

所以问题确实出在boost::fast_pool_allocator和 上boost::pool_allocator,而且回想起来似乎有点明显。问题的基本症结是 boost分配器构造方法是根据 c++98 标准分配器规范实现的,并且有一个构造方法,该方法采用单个 const& 参数,用于在新的放置中复制构造对象。c++11 风格使用可变参数模板,并且参数被传递给通过放置 new 创建的对象的构造函数。在我的测试代码的特定情况下,正是没有传递初始化值的变体std::allocate_shared导致了错误。当前的核心问题是 c++11std::allocate_shared试图将可变数量的参数传递给construct()只接受一个的方法。在我的测试中,当只有一个值传入并且不会被其他变体调用时,我可以在构造方法上断点。例如,如果您要分配std::pair<>(2 个参数),则根本不会调用构造方法,并且必须使用其他一些机制。我对此进行了一些跟踪,它看起来像是std::allocate_shared在内部包装了构造调用,如果对构造的调用不匹配,则调用替代方法(通过隐式函数查找)直接构造对象。下面最上面的方法调用construct()分配器的方法,下面的方法直接new对象:

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

这是我有时间真正识别编译错误根源的时间,但这足以让我为问题提出一个简单而有效的解决方案。

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

void construct(const pointer ptr, const value_type & t)
{ new (ptr) T(t); }
Run Code Online (Sandbox Code Playgroud)

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

这似乎是 boost 没有更新其代码以支持 c++11 的一个错误,但 g++5.0(我确认)编译没有问题的事实意味着添加此支持并不是强制性的。可能是为了std::allocate_shared向后兼容旧的分配器接口,而 4.7、4.8 和 4.9 上的崩溃和编译错误是因为支持被破坏。我会在 boost bug tracker 上发布一张票,看看他们认为这笔交易是什么:boost trac Ticket