9

EDIT:

Clarifying my desired outcome because I haven't communicated it well:
To be able to use std::allocate_shared with boost::fast_pool_allocator as the allocation method using g++ 4.8 or higher with boost 1.56.0. Currently this works on g++ 4.6 and fails on 4.7, 4.8 and 4.9.

To be clear, I am not looking to have this work for g++4.7.

Test code to produce errors:

#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);
}

In our code base we have usage of std::allocate_shared in combination with the boost pool allocators and this results in some nasty compile errors. However this has morphed and changed across different versions of g++:
details: 64bit, (4.7,4.8) -std=c++11, (4.6) -std=c++0x, boost 1.56.0
4.6 - Compiles happily
4.7 - Crashes the compiler

Internal compiler error: Error reporting routines re-entered. Please submit a full bug report, with preprocessed source if appropriate. See for instructions. Preprocessed source stored into /tmp/cca0Emq9.out file, please attach this to your bugreport.

4.8 - Nasty compile errors

/XXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399:

error: use of deleted function ‘std::_Sp_counted_ptr_inplace, (__gnu_cxx::_Lock_policy)2u>::_Sp_counted_ptr_inplace(const std::_Sp_counted_ptr_inplace, (__gnu_cxx::_Lock_policy)2u>&)’ { new (ptr) T(t); } ^

/usr/include/c++/4.8/bits/shared_ptr_base.h:198: error: ‘std::_Sp_counted_base<_Lp>::_Sp_counted_base(const std::_Sp_counted_base<_Lp>&) [with __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’ is private _Sp_counted_base(_Sp_counted_base const&) = delete; ^ /usr/include/c++/4.8/bits/shared_ptr_base.h:379: error: within this context class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> ^

/usr/include/c++/4.8/bits/shared_ptr_base.h:379: error: use of deleted function ‘std::_Sp_counted_base<_Lp>::_Sp_counted_base(const std::_Sp_counted_base<_Lp>&) [with __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’

/usr/include/c++/4.8/bits/shared_ptr_base.h:198: error: declared here _Sp_counted_base(_Sp_counted_base const&) = delete; ^

4.9 - Nasty compile errors (slightly different)

/XXXXXXXXXXX/boost/boost/pool/pool_alloc.hpp:399: error: use of deleted function ‘std::_Sp_counted_ptr_inplace, (__gnu_cxx::_Lock_policy)2u>::_Sp_counted_ptr_inplace(const std::_Sp_counted_ptr_inplace, (__gnu_cxx::_Lock_policy)2u>&)’ { new (ptr) T(t); } ^

/usr/include/c++/4.9/bits/shared_ptr_base.h:203: error: ‘std::_Sp_counted_base<_Lp>::_Sp_counted_base(const std::_Sp_counted_base<_Lp>&) [with __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’ is private _Sp_counted_base(_Sp_counted_base const&) = delete; ^

/usr/include/c++/4.9/bits/shared_ptr_base.h:494: error: within this context class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp> ^

/usr/include/c++/4.9/bits/shared_ptr_base.h:494: error: use of deleted function ‘std::_Sp_counted_base<_Lp>::_Sp_counted_base(const std::_Sp_counted_base<_Lp>&) [with __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’

I have spent a significant amount of time trying to get to the bottom of this and I some assistance would be appreciated if anyone is more familiar with the inner workings of these components.

radman
  • 17,675
  • 11
  • 42
  • 58
  • 4
    Internal Compiler errors are _always_ bugs reportable to the vendor, SO can't help with that. – sehe Oct 16 '14 at 06:38
  • I have a hunch this is more of a standard library change than a compiler change. – sehe Oct 16 '14 at 06:42
  • 1
    As suggested by @Sehe, this is an issue with the standard library implementation rather than the compiler. I've tried this in (GCC) 5.0.0 20141022 (experimental) and it compiles. –  Oct 22 '14 at 03:54
  • I must admit I'm confused you have even put a bounty on a question that is clearly about a compiler bug. If you wanted to ask about workarounds, could you edit the question accordingly? – sehe Oct 22 '14 at 10:34
  • On g++ 4.8.3 `auto fails = std::allocate_shared( std::allocator());` does not fail so boost must be using something that is not implemented yet in 4.7. – Surt Oct 22 '14 at 14:52
  • From the description you can see the test code works on g++ 4.6 and fails on g++ 4.7 4.8 and 4.9. It crashes 4.7 but I'm more concerned in getting it working on 4.8+. 4.7 is obviously a lost cause. – radman Oct 22 '14 at 22:48
  • Since boost try to keep backward compability even with no more existing compilers is probably due to the fact that some workaround to keep it working on old versions is causing it to no working on recent versions. I always feared that boost would one day or another crash the compilers due to heavy templates usage :D. – CoffeDeveloper Oct 23 '14 at 05:50
  • This question may help get you further along, but I realize it doesn't completely answer your question: http://stackoverflow.com/questions/5966698/error-use-of-deleted-function – Jonathan Oct 28 '14 at 16:58

2 Answers2

3

I spent a lot of time looking at different compiler versions under the assumption that this was a compiler bug as suggested by the crash in g++4.7 and the comments of the other answerers/commenters. However after going back to the compile errors and digging at them for a while I managed to finally understand the cause of the compile errors with some level of specificity.

So the problem truly is in the boost::fast_pool_allocator and boost::pool_allocator and it seems a little obvious in retrospect. The basic crux of the problem is that the boost allocators construct method is implemented in terms of the c++98 standard allocator spec and have a construct method that takes a single const& param that is used to copy construct an object in a placement new. The c++11 style uses variadic templates and the args are passed to a constructor for the object being created via placement new. In the particular case of my test code it is the variant that passes no initialising value to std::allocate_shared that causes the errors. The core issue at hand is that c++11 std::allocate_shared is trying to pass down a variable number of arguments to a construct() method that only takes one. In my tests I can breakpoint the construct method when there is exactly one value passed in and it doesn't get called for other variants. For example if you are allocating a std::pair<> (2 params) then the construct method is not called at all and some other mechanism must be used. I traced this for a bit and it looks like std::allocate_shared wraps the construct call internally and if the call to construct doesn't match then an alternate method is called (via implicit function lookup) which constructs the object directly. The top method below calls the construct() method of the allocator, the bottom one new's the object directly:

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)...); }

This is as far as I have time to go in really identifying the source of the compile errors but this was enough for me to put together a simple and effective solution to the problem.

The solution here is straightforward; boost needs to be updated to use the new c++11 allocator spec. Doing this is actually very straightforward; in pool_alloc.hpp replace all instances of:

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

with

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

It seems like this is a bug with boost not updating their code for c++11 support but the fact that g++5.0 (which I confirmed) compiles without issues implies that adding this support isn't mandatory going forward. It could be that std::allocate_shared is intended to be backwards compatible with the old allocator interface and the crash and compile errors on 4.7, 4.8 and 4.9 was that support being broken. I'll post a ticket on the boost bug tracker and see what they think the deal is: boost trac ticket

radman
  • 17,675
  • 11
  • 42
  • 58
2

Since this appears to be a problem(?) with libstdc++, you can use the boost equivalent of the standard library functions instead boost::allocate_shared. Include <boost/make_shared.hpp>. Here's a Coliru demo showing four different GCC versions that compile fine. As I mentioned in the comments, std::allocate_shared works with a trunk build of GCC and with libc++. I'm unable to find an existing bug report related to this problem but you can file one for GCC or for Boost.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • hi, I had already looked at `boost::allocate_shared` and the problem is that I need `std::shared_ptr`'s out rather than their boost equivalents. The title of my question is somewhat misleading, so I'll clarify; I need to be able to use `std::allocate_shared` with the boost pool allocators specified as the allocation method. – radman Oct 23 '14 at 05:20