Bug 16026 - basic_string & STL containers expect conflicting allocator types
Summary: basic_string & STL containers expect conflicting allocator types
Keywords:
Status: CLOSED UPSTREAM
Alias: None
Product: Red Hat Linux
Classification: Retired
Component: gcc
Version: 7.0
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2000-08-11 20:39 UTC by fwx
Modified: 2007-04-18 16:28 UTC (History)
0 users

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2004-10-01 15:51:03 UTC
Embargoed:


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

Description fwx 2000-08-11 20:39:45 UTC
// 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
fspam

*/

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

#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
	{
	public:
		// 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>
			my_allocator( 
				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; }

#ifdef USE_NONSTANDARD_ALLOCATOR
		// 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); }
#else
		// 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); }
#endif

		// 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>&);

	private:
		// 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;

typedef 
	basic_string< char, string_char_traits<char>, my_allocator<char> > 
	my_char_string;

typedef 
	vector< char, my_allocator<char> > 
	my_char_vector;

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 20:41:02 UTC
Created attachment 2414 [details]
Demonstration of libstdc++ basic_string / STL container allocator conflict.

Comment 2 Benjamin Kosnik 2004-10-01 15:51:03 UTC
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
requirements.

-benjamin


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