提升池分配器不会在 g++ 中使用 std::allocate_shared 进行编译
Boost pool allocators won't compile with std::allocate_shared in g++
编辑:
澄清我想要的结果,因为我没有很好地沟通:
能够使用std::allocate_shared
和boost::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与提升池分配器结合使用,这会导致一些严重的编译错误。然而,这在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文件中,请附上这是你的错误报告。
4.8-讨厌的编译错误
/XXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399:
错误:使用已删除的函数'std::_Sp_counted_prt_inplace,(__gnu_cxx::_Lock_policy)2u>::_Sp_counted_ptr_inplace(conststd::_Sp_counted_ptr_inplace,(__gnu_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(常量std::_Sp_counted_base<_Lp>&)[带有__gnu_cxx::_Lock_policy_Lp=(__gnu_cxx::_Lock_policy)2u]'是私有的_Sp_counted_base(_Sp_counted_base const&)=删除;^/usr/include/c++/4.8/bits/shared_ptr_base.h:379:错误:在此上下文class_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(常量std::_Sp_counted_base<_Lp>&)[带有__gnu_cxx::_Lock_policy_Lp=(__gnu_cxx::_Lock_policy)2u]'
/usr/include/c++/4.8/bits/shared_ptr_base.h:198:错误:在此处声明_Sp_counted_base(_Sp_counted_base const&)=删除;^
4.9-讨厌的编译错误(略有不同)
/XXXXXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399:错误:使用删除了函数'std::_Sp_counted_prt_inplace,(__gnu_cxx::_Lock_policy)2u>::_Sp_counted_ptr_inplace(conststd::_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(常量std::_Sp_counted_base<_Lp>&)[带有__gnu_cxx::_Lock_policy_Lp=(__gnu_cxx::_Lock_policy)2u]'是私有的_Sp_counted_base(_Sp_counted_base const&)=删除;^
/usr/include/c++/4.9/bits/shared_ptr_base.h:494:错误:在此上下文class_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(常量std::_Sp_counted_base<_Lp>&)[带有__gnu_cxx::_Lock_policy_Lp=(__gnu_cxx::_Lock_policy)2u]'
我花了大量的时间试图弄清真相,我会得到一些帮助如果有人更熟悉这些组件。
我花了很多时间研究不同的编译器版本,假设这是g++4.7中的崩溃和其他回答者/评论者的评论所暗示的编译器错误。然而,在回到编译错误并深入研究了一段时间后,我终于在一定程度上具体了解了编译错误的原因。
因此,问题确实存在于boost::fast_pool_allocator
和boost::pool_allocator
中,回顾起来似乎有点明显。问题的基本症结在于,boost分配器构造方法是根据c++98标准分配器规范实现的,并且具有采用单个常量&用于在新位置复制构造对象的param。c++11样式使用可变模板,参数通过placementnew传递给正在创建的对象的构造函数。在我的测试代码的特定情况下,导致错误的是没有将初始化值传递给std::allocate_shared
的变体。当前的核心问题是,c++11std::allocate_shared
试图将可变数量的参数传递给只需要一个参数的construct()
方法。在我的测试中,当正好有一个值传入并且没有为其他变体调用时,我可以中断构造方法。例如,如果您正在分配std::pair<>
(2个参数),则根本不调用构造方法,必须使用其他机制。我对此进行了跟踪,看起来std::allocate_shared
在内部封装了构造调用,如果对构造的调用不匹配,则调用一个替代方法(通过隐式函数查找),该方法直接构造对象。下面最上面的方法调用分配器的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)... );
}
这似乎是一个bug,boost没有更新他们的代码以支持c++11,但g++5.0(我确认了这一点)编译没有问题,这意味着添加这种支持并不是强制性的。std::allocate_shared
可能是为了与旧的分配器接口向后兼容,4.7、4.8和4.9上的崩溃和编译错误就是这种支持被破坏的原因。我会在boost bug跟踪器上发布一张票证,看看他们认为交易是什么:boost trac票证
由于这似乎是libstdc++的问题(?),您可以使用标准库函数的boost等价物来代替boost::allocate_shared
。包括<boost/make_shared.hpp>
。这里有一个Coliru演示,显示了四个编译良好的不同GCC版本。正如我在评论中提到的,std::allocate_shared
使用GCC的主干构建和libc++。我找不到与此问题相关的现有错误报告,但您可以为GCC或Boost提交一份。
- 使用std::multimap迭代器创建std::list
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如何导出包含具有"std::unique_ptr"值的"std::map"属性的
- 从持续时间构造std::chrono::system_clock::time_point
- std::具有相同基类的类的变体
- std::向量与传递值的动态数组
- 使用std::vector的OpenCL矩阵乘法
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- std::condition_variable::wait()如何评估给定的谓词
- 如何获取std::result_of函数的返回类型
- std::原子加载和存储都需要吗
- 将对象移动到std::shared_ptr
- POCO::PostgreSQL:如何将std::vector支持添加到`Binder::bind`
- 使用一个考虑到std::map中键值的滚动或换行的键
- 如何从 std::atomic 中提取指针 T<T>?
- 为什么 std::unique 不调用 std::sort?
- 如何测试分配器是否使用std::allocate进行内存分配
- 是否保证std::vector每次使用allocate函数分配的内存,也会通过单个deallocate调用立即释放?