Skip to content

Commit 49fd590

Browse files
Joe Herdmanjeking3
authored andcommitted
Allow object_pool::construct() to use variadic template, if available.
1 parent a727155 commit 49fd590

File tree

3 files changed

+127
-0
lines changed

3 files changed

+127
-0
lines changed

include/boost/pool/object_pool.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,18 @@ class object_pool: protected pool<UserAllocator>
175175
//! detail/pool_construct.bat and detail/pool_construct.sh are also provided to call m4, defining NumberOfArguments
176176
//! to be their command-line parameter. See these files for more details.
177177
}
178+
#elif defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS)
179+
// When available, use variadic templates to avoid the older '.ipp'/'.m4' implementation
180+
template <typename... Args>
181+
element_type * construct(Args&&... args)
182+
{
183+
element_type* const ret = (malloc)();
184+
if (ret == 0)
185+
return ret;
186+
try { new (ret) element_type(std::forward<Args>(args)...); }
187+
catch (...) { (free)(ret); throw; }
188+
return ret;
189+
}
178190
#else
179191
// Include automatically-generated file for family of template construct() functions.
180192
// Copy .inc renamed .ipp to conform to Doxygen include filename expectations, PAB 12 Jan 11.

include/boost/pool/pool.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,8 @@ class pool
969969
if(free_list.empty())
970970
{
971971
ret = (user_allocator::malloc)(chunk_size);
972+
if ( ret == 0 )
973+
return ret;
972974
VALGRIND_MAKE_MEM_UNDEFINED(ret, chunk_size);
973975
}
974976
else

test/test_pool_alloc.cpp

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ class cdtor_checker
4848

4949
void check_out(void * const This)
5050
{
51+
// Under current usage, 'This' is the 'this'-pointer of a 'tester' object.
52+
// If it is NULL here, then something has already gone terribly wrong
53+
BOOST_TEST(This != NULL);
54+
5155
BOOST_TEST(objs.find(This) != objs.end());
5256
objs.erase(This);
5357
}
@@ -66,6 +70,25 @@ struct tester
6670
mem.check_in(this);
6771
}
6872

73+
tester(int a0, int a1)
74+
{
75+
set_values(a0, a1, -1, -1);
76+
77+
mem.check_in(this);
78+
}
79+
80+
tester(int a0, const int& a1, int a2, const int a3, bool throw_except = false)
81+
{
82+
if(throw_except)
83+
{
84+
throw std::logic_error("Deliberate constructor exception");
85+
}
86+
87+
set_values(a0, a1, a2, a3);
88+
89+
mem.check_in(this);
90+
}
91+
6992
tester(const tester &)
7093
{
7194
mem.check_in(this);
@@ -75,6 +98,32 @@ struct tester
7598
{
7699
mem.check_out(this);
77100
}
101+
102+
int stored_a0;
103+
int stored_a1;
104+
int stored_a2;
105+
int stored_a3;
106+
107+
void set_values(int a0, int a1, int a2, int a3)
108+
{
109+
stored_a0 = a0;
110+
stored_a1 = a1;
111+
stored_a2 = a2;
112+
stored_a3 = a3;
113+
}
114+
115+
void check_values(int a0, int a1)
116+
{
117+
check_values(a0, a1, -1, -1);
118+
}
119+
120+
void check_values(int a0, int a1, int a2, int a3)
121+
{
122+
BOOST_TEST( a0 == stored_a0 );
123+
BOOST_TEST( a1 == stored_a1 );
124+
BOOST_TEST( a2 == stored_a2 );
125+
BOOST_TEST( a3 == stored_a3 );
126+
}
78127
};
79128

80129
// This is a wrapper around a UserAllocator. It just registers alloc/dealloc
@@ -113,6 +162,23 @@ std::set<char *> TrackAlloc<UserAllocator>::allocated_blocks;
113162

114163
typedef TrackAlloc<boost::default_user_allocator_new_delete> track_alloc;
115164

165+
// This is a simple UserAllocator to allow coverage-testing of the codepath
166+
// where memory allocation fails.
167+
struct always_fails_allocation_alloc
168+
{
169+
typedef std::size_t size_type;
170+
typedef std::ptrdiff_t difference_type;
171+
172+
static char * malloc(const size_type /*bytes*/)
173+
{
174+
return 0;
175+
}
176+
177+
static void free(char * const /*block*/)
178+
{
179+
}
180+
};
181+
116182
void test()
117183
{
118184
{
@@ -162,6 +228,53 @@ void test()
162228
}
163229
catch(const std::logic_error &) {}
164230
}
231+
#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS)
232+
for(int k=0; k < 5; ++k)
233+
{
234+
try
235+
{
236+
// The following constructions will raise an exception.
237+
pool.construct(k,2*k,3*k,4*k,true);
238+
}
239+
catch(const std::logic_error &) {}
240+
}
241+
#endif
242+
}
243+
244+
{
245+
// Test the 'pool.construct' with 2 ctor parameters
246+
boost::object_pool<tester> pool;
247+
for(int i=0; i < 5; ++i)
248+
{
249+
tester * newItem = pool.construct(i, 2*i);
250+
newItem->check_values(i, 2*i);
251+
}
252+
}
253+
254+
#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS)
255+
{
256+
// Test the 'pool.construct' with 4 ctor parameters
257+
// Without variadic-templates, this functionality requires
258+
// that the end-user has run the 'detail/pool_construct.m4'
259+
// functionality to generate a larger set of 'construct()'
260+
// overloads. [see docs for object_pool::construct()]
261+
boost::object_pool<tester> pool;
262+
for(int i=0; i < 5; ++i)
263+
{
264+
tester * newItem = pool.construct(i, 2*i, 3*i, 5*i);
265+
newItem->check_values(i, 2*i, 3*i, 5*i);
266+
}
267+
}
268+
#endif
269+
270+
{
271+
// Test the case where memory allocation intentionally fails
272+
boost::object_pool<tester, always_fails_allocation_alloc> pool;
273+
BOOST_TEST( pool.construct() == 0 );
274+
BOOST_TEST( pool.construct(1,2) == 0 );
275+
#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS)
276+
BOOST_TEST( pool.construct(1,2,3,4) == 0 );
277+
#endif
165278
}
166279
}
167280

0 commit comments

Comments
 (0)