c++11 std containers must construct value_type using allocator?
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi!
I'm playing around with allocators in c++11 using clang+libcxx. I've
come across a problem in range-constructing a list from iterators over
a different value_type.
My central question: Is a std container allowed to construct any
instances of its value_type without using the construct method of the
allocator?
I have the expectation that it should. Suppose the following
implementation of a std::list range constructor. If the
Iter::value_type differs from the list::value_type, may the list
construct a temporary list::value_type in the call to push_back? This
one would bypass the allocator.
template<typename T, typename Alloc>
template<typename Iter>
list<T, Alloc>::list(Iter first, Iter last, Alloc const& a)
: alloc_instance(a)
{
for(; first!=last; ++first)
push_back(*first); //temporary without allocator
}
If using a list with a custom allocator that augments the construction
of the value_type (like scoped_allocator_adaptor) it follows that the
range Iter::value_type must be the same as the list::value_type. Any
convenience of conversions within the constructor are gone.
Complete example here:
#include <cstdlib>
#include <memory>
#include <scoped_allocator>
#include <string>
#include <list>
//**********************************
// custom allocator
// simple example using malloc/free:
template<typename T>
struct mallocfree
{
/* Any allocator with state may have no
* default constructor.
*/
mallocfree(char) {} // no default ctor
// converting constructor:
template<typename U>
mallocfree(mallocfree<U> const& other) {}
typedef T value_type;
T* allocate(size_t const n)
{
if(void* const p = std::malloc(sizeof(T)*n))
return static_cast<T*>(p);
throw std::bad_alloc();
}
void deallocate(T* const p, size_t) noexcept
{
std::free(static_cast<void*>(p));
}
};
template<typename T>
inline constexpr bool operator == (
mallocfree<T> const&,
mallocfree<T> const&
)
{ return true; }
//**************************************
// Typedefs for list<string> with alloc:
template<typename T>
using my_alloc = std::scoped_allocator_adaptor<
mallocfree<T>>;
typedef std::basic_string<
char,
std::char_traits<char>,
my_alloc<char>
AugmentedString;
typedef std::list<
AugmentedString,
my_alloc<AugmentedString>
AugmentedList;
//*************
// MAIN
int main()
{
auto inits = {"a", "b", "c"};
// ctor fails on push_back:
AugmentedList l(
inits.begin(),
inits.end(),
my_alloc<AugmentedString>('a')
);
}
Errors from clang 3.3 shows default ctor of mallocfree is requested
from a list constructor that uses push_back:
/opt/local/libexec/llvm-3.3/bin/../lib/c++/v1/scoped_allocator:270:5:
error: constructor for
'std::__1::__scoped_allocator_storage<mallocfree<char> >' must
explicitly initialize the base class 'mallocfree<char>' which does not
have a default constructor
__scoped_allocator_storage() _NOEXCEPT {}
^
/opt/local/libexec/llvm-3.3/bin/../lib/c++/v1/scoped_allocator:410:5:
note: in instantiation of member function
'std::__1::__scoped_allocator_storage<mallocfree<char>
::__scoped_allocator_storage' requested here
scoped_allocator_adaptor() _NOEXCEPT {}
^
....
/opt/local/libexec/llvm-3.3/bin/../lib/c++/v1/list:1104:19: note: in
instantiation of member function 'std::__1::basic_string<char,
std::__1::char_traits<char>,
std::__1::scoped_allocator_adaptor<mallocfree<char> > >::basic_string'
requested here
push_back(*__f);
^
....
Frank
-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
Comment: GPGTools - http://gpgtools.org
Comment: keyserver x-hkp://pool.sks-keyservers.net
iEYEARECAAYFAlDyjnIACgkQhAOUmAZhnmr5cQCfV7lslb8zZWR72EDmNP27APWd
DOUAmwbVwudQIgxGtazIH0TXDjF/HpCV
=7eS2
-----END PGP SIGNATURE-----
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]