diff --git a/include/boost/pool/object_pool.hpp b/include/boost/pool/object_pool.hpp index 55da60b..0d86d45 100644 --- a/include/boost/pool/object_pool.hpp +++ b/include/boost/pool/object_pool.hpp @@ -175,6 +175,18 @@ class object_pool: protected pool //! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments //! to be their command-line parameter. See these files for more details. } +#elif defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + // When available, use variadic templates to avoid the older '.ipp'/'.m4' implementation + template + element_type * construct(Args&&... args) + { + element_type* const ret = (malloc)(); + if (ret == 0) + return ret; + try { new (ret) element_type(std::forward(args)...); } + catch (...) { (free)(ret); throw; } + return ret; + } #else // Include automatically-generated file for family of template construct() functions. // Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11. diff --git a/include/boost/pool/pool.hpp b/include/boost/pool/pool.hpp index 12728a7..225397b 100644 --- a/include/boost/pool/pool.hpp +++ b/include/boost/pool/pool.hpp @@ -969,6 +969,8 @@ class pool if(free_list.empty()) { ret = (user_allocator::malloc)(chunk_size); + if ( ret == 0 ) + return ret; VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size); } else diff --git a/test/test_pool_alloc.cpp b/test/test_pool_alloc.cpp index b0b50ea..587bd4e 100644 --- a/test/test_pool_alloc.cpp +++ b/test/test_pool_alloc.cpp @@ -48,6 +48,10 @@ class cdtor_checker void check_out(void * const This) { + // Under current usage, 'This' is the 'this'-pointer of a 'tester' object. + // If it is NULL here, then something has already gone terribly wrong + BOOST_TEST(This != NULL); + BOOST_TEST(objs.find(This) != objs.end()); objs.erase(This); } @@ -66,6 +70,25 @@ struct tester mem.check_in(this); } + tester(int a0, int a1) + { + set_values(a0, a1, -1, -1); + + mem.check_in(this); + } + + tester(int a0, const int& a1, int a2, const int a3, bool throw_except = false) + { + if(throw_except) + { + throw std::logic_error("Deliberate constructor exception"); + } + + set_values(a0, a1, a2, a3); + + mem.check_in(this); + } + tester(const tester &) { mem.check_in(this); @@ -75,6 +98,32 @@ struct tester { mem.check_out(this); } + + int stored_a0; + int stored_a1; + int stored_a2; + int stored_a3; + + void set_values(int a0, int a1, int a2, int a3) + { + stored_a0 = a0; + stored_a1 = a1; + stored_a2 = a2; + stored_a3 = a3; + } + + void check_values(int a0, int a1) + { + check_values(a0, a1, -1, -1); + } + + void check_values(int a0, int a1, int a2, int a3) + { + BOOST_TEST( a0 == stored_a0 ); + BOOST_TEST( a1 == stored_a1 ); + BOOST_TEST( a2 == stored_a2 ); + BOOST_TEST( a3 == stored_a3 ); + } }; // This is a wrapper around a UserAllocator. It just registers alloc/dealloc @@ -113,6 +162,23 @@ std::set TrackAlloc::allocated_blocks; typedef TrackAlloc track_alloc; +// This is a simple UserAllocator to allow coverage-testing of the codepath +// where memory allocation fails. +struct always_fails_allocation_alloc +{ + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static char * malloc(const size_type /*bytes*/) + { + return 0; + } + + static void free(char * const /*block*/) + { + } +}; + void test() { { @@ -162,6 +228,53 @@ void test() } catch(const std::logic_error &) {} } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + for(int k=0; k < 5; ++k) + { + try + { + // The following constructions will raise an exception. + pool.construct(k,2*k,3*k,4*k,true); + } + catch(const std::logic_error &) {} + } +#endif + } + + { + // Test the 'pool.construct' with 2 ctor parameters + boost::object_pool pool; + for(int i=0; i < 5; ++i) + { + tester * newItem = pool.construct(i, 2*i); + newItem->check_values(i, 2*i); + } + } + +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + { + // Test the 'pool.construct' with 4 ctor parameters + // Without variadic-templates, this functionality requires + // that the end-user has run the 'detail/pool_construct.m4' + // functionality to generate a larger set of 'construct()' + // overloads. [see docs for object_pool::construct()] + boost::object_pool pool; + for(int i=0; i < 5; ++i) + { + tester * newItem = pool.construct(i, 2*i, 3*i, 5*i); + newItem->check_values(i, 2*i, 3*i, 5*i); + } + } +#endif + + { + // Test the case where memory allocation intentionally fails + boost::object_pool pool; + BOOST_TEST( pool.construct() == 0 ); + BOOST_TEST( pool.construct(1,2) == 0 ); +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + BOOST_TEST( pool.construct(1,2,3,4) == 0 ); +#endif } }