Bug 16026 - basic_string & STL containers expect conflicting allocator types
basic_string & STL containers expect conflicting allocator types
Product: Red Hat Linux
Classification: Retired
Component: gcc (Show other bugs)
All Linux
medium Severity medium
: ---
: ---
Assigned To: Jakub Jelinek
Depends On:
  Show dependency treegraph
Reported: 2000-08-11 16:39 EDT by fwx
Modified: 2007-04-18 12:28 EDT (History)
0 users

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Last Closed: 2004-10-01 11:51:03 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---

Attachments (Terms of Use)
Demonstration of libstdc++ basic_string / STL container allocator conflict. (5.02 KB, text/plain)
2000-08-11 16:41 EDT, fwx
no flags Details

  None (edit)
Description fwx 2000-08-11 16:39:45 EDT
// demoalloc.C

11 August 2000

This program is intended to demonstrate a problem in the GNU Standard C++ 
Library which accompanies gcc 2.96 and 2.95.2.  I have reproduced the 
same results on the Red Hat 7.0 (Pinstripe) beta, and on Linux Mandrake
7.0 (Air).

The problem I have encountered is a discrepancy between allocator types
expected by standard library classes.  The STL container classes requires
an allocator that follows the C++ standard, while the basic_string class
requires an allocator that deviates from the standard.  Specifically, the
latter expects an allocator class to contain static allocate() and
deallocate() member functions, whose arguments represent a number of bytes
(rather than a number of objects).

The result is that I cannot use strings and STL containers together in the 
same code, when I require them to use a non-default allocator.  Examples
of such cases include "plug-in" code designed to extend PostgreSQL, PHP, 
and Apache.  These programs (and many others) have their own memory
management routines, which means that plug-ins using C++ strings and STL
containers must use allocators that call said routines.  In other words,
the default allocators are not an option in these cases.

With libstdc++ in its current state, a coder in this situation would have
to create two different versions of each allocator, to even hope for a
working system.

reported by:

Forest Wilkinson


// Uncomment this line to define an allocator that works with the 
// basic_string class in libstdc++:

#include <algorithm>
#include <cstddef>
#include <cstdlib>
#include <climits>
#include <string>
#include <vector>

// === C++ allocator class ===
// (uses malloc/free behind the scenes, and does not throw exceptions)

// The allocator clas itself:
template< class T>
class my_allocator
		// types:
		typedef T value_type;
		typedef std::size_t size_type;
		typedef std::ptrdiff_t difference_type;

		typedef T* pointer;
		typedef const T* const_pointer;

		typedef T& reference;
		typedef const T& const_reference;

		template< class U> 
			struct rebind 
				typedef my_allocator<U> other; 
				}; // in effect: typedef my_allocator<U> other

		// 'structors:
		my_allocator() throw() {}
		template< class U>
				const my_allocator<U> &foreign_al) throw() {}
		~my_allocator() throw() {}

		// operations:

		pointer address( reference r) const { return &r; }
		const_pointer address( const_reference r) const { return &r; }

		// allocate space for n bytes:
		static void *allocate( size_t nbytes)
			{ return std::malloc( nbytes); }
		// deallocate n bytes:
		static void deallocate( void *p, size_t nbytes )
			{ std::free( p); }
		// allocate space for n objects of type T:
		pointer allocate( size_type n, const void* hint = 0)
			{ return static_cast<pointer>( std::malloc( n * sizeof(T))); }
		// deallocate n objects of type T:
		void deallocate( pointer p, size_type /* n */ )
			{ std::free( p); }

		// initialize *p with val:
		void construct( pointer p, const T& val)
			{ new(static_cast<const void *>(p)) T(val); }
		// destroy *p (don't deallocate it):
		void destroy( pointer p)
			{ p->~T(); }

		size_type max_size() const throw()
			{ return std::max( size_type(1), size_type( UINT_MAX/sizeof(T)));}

		friend bool operator==<>( 
			const my_allocator<T>&, const my_allocator<T>&);
		friend bool operator!=<>( 
			const my_allocator<T>&, const my_allocator<T>&);

		// helper function, which allocates chars or throws an exception:
		static void *alloc_or_throw( size_t nchars);

According to Stroustrup 3 (sec. 19.4.2 and 19.4.3), and
the C++ Standard (ISO 14882 sec. 20.1.5):
Standard container implementations may treat all allocators
of the same type as equivalent.  
This makes operators == and != simpler, as they always 
return true and false, respectively.

Two my_allocator objects should compare equal if one was
constructed from the other.
template< class T> 
inline bool operator==( 
	const my_allocator<T>& a,
	const my_allocator<T>& b) throw()
	return true;

Two my_allocator objects should compare equal if one was
constructed from the other.
template< class T> 
inline bool operator!=( 
	const my_allocator<T>& a,
	const my_allocator<T>& b) throw()
	return false;

// === main part of our demonstration ===

using namespace std;

	basic_string< char, string_char_traits<char>, my_allocator<char> > 

	vector< char, my_allocator<char> > 

int main( int argc, char *argv[])
	// This section compiles when my_allocator follows the C++ standard,
	// and defines per-opbject allocate/deallocate functions:
	my_char_vector iv;
	iv.push_back( 'a');
	iv.push_back( 'b');
	iv.erase( iv.begin());

	// This section compiles only when my_allocator deviates from  the C++ 
	// standard, by defining static per-byte allocate/deallocate functions:
	my_char_string str;
	str = my_char_string( "hello, world.");

	return 0;

// === eof ===
Comment 1 fwx 2000-08-11 16:41:02 EDT
Created attachment 2414 [details]
Demonstration of libstdc++ basic_string / STL container allocator conflict.
Comment 2 Benjamin Kosnik 2004-10-01 11:51:03 EDT
This is indeed a bug in the libstdc++ implementation pre-3.4. For the
3.4 libstdc++ release, we've fixed this.

This fix will not be ported to previous versions due to ABI stability


Note You need to log in before you can comment on or make changes to this bug.