Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Custom allocator not working with gcc

65 views
Skip to first unread message

bol...@nowhere.co.uk

unread,
May 9, 2020, 5:50:44 AM5/9/20
to
Hi

Despite having worked with C++ for years I've never bothered with STL custom
allocators before. However now I need to. Using some code from various sources
I created a very simple custom allocator below which works perfectly in Clang
but not in 2 seperate versions of gcc which never call the allocate() or
deallocate() functions even though the code compiles fine. I'm sure I've made
some stupid error but I can't see what. Can anyone help?

Many thanks

#include <iostream>
#include <memory>
#include <vector>
#include <string>

#include <stdio.h>
#include <stdlib.h>

using namespace std;


template<typename T>
class myallocator: public allocator<T>
{
public:
T *allocate(size_t cnt, const void *hint=0)
{
T *ptr;
size_t bytes;
bytes = cnt * sizeof(T);
printf("Allocating %ld instances, %lu bytes\n",cnt,bytes);
ptr = (T *)malloc(bytes);
printf("Pointer = %lu\n",(u_long)ptr);
return ptr;
}

void deallocate(T *ptr, size_t cnt)
{
printf("Deallocating pointer %lu\n",(u_long)ptr);
free(ptr);
}
};


int main()
{
puts("Creating vector...");
vector<int,myallocator<int> > v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << "-----\n";

// String uses built in array for small strings
puts("Creating string...");
basic_string<char,char_traits<char>,myallocator<char> > s = "12345";
puts("Appending string...");
// This will force allocation
s += "6789012345678901234567890";

puts("End");
return 0;
}

Ian Collins

unread,
May 9, 2020, 6:22:59 AM5/9/20
to
On 09/05/2020 21:50, bol...@nowhere.co.uk wrote:
> Hi
>
> Despite having worked with C++ for years I've never bothered with STL custom
> allocators before. However now I need to. Using some code from various sources
> I created a very simple custom allocator below which works perfectly in Clang
> but not in 2 seperate versions of gcc which never call the allocate() or
> deallocate() functions even though the code compiles fine. I'm sure I've made
> some stupid error but I can't see what. Can anyone help?
>
> Many thanks

Your code as posted won't compile (the string construction).

In short, don't derive from std::allocator! Also, don't mix iostreams
with C stdio.

> #include <iostream>
> #include <memory>
> #include <vector>
> #include <string>
>
> #include <stdio.h>
> #include <stdlib.h>
>
> using namespace std;
>
>
> template<typename T>
> class myallocator: public allocator<T>

class myallocator

> {
> public:
using value_type = T;

> T *allocate(size_t cnt, const void *hint=0)

T *allocate(size_t count)
--
Ian.

Juha Nieminen

unread,
May 9, 2020, 6:29:43 AM5/9/20
to
bol...@nowhere.co.uk wrote:
> I created a very simple custom allocator below which works perfectly in Clang
> but not in 2 seperate versions of gcc which never call the allocate() or
> deallocate() functions even though the code compiles fine. I'm sure I've made
> some stupid error but I can't see what. Can anyone help?

The problem seems to be that you are inheriting from std::allocator.
I'm not exactly sure why, but it may well be that the library
implementation is doing some kind of shortcut if the allocator is
of type std::allocator.

You can fix it by not inheriting from std::allocator. Simply remove
that inheritance and add this to your class:

using value_type = T;

> printf("Allocating %ld instances, %lu bytes\n",cnt,bytes);

You should be using "%zu" for std::size_t type values.

> printf("Pointer = %lu\n",(u_long)ptr);

No such thing s "u_long". And you probably want to use "%p" for
pointers.

Juha Nieminen

unread,
May 9, 2020, 6:31:09 AM5/9/20
to
Ian Collins <ian-...@hotmail.com> wrote:
> Also, don't mix iostreams with C stdio.

As long as they are synced (which is possible via standard library)
it becomes merely a question of program design rather than validity.

bol...@nowhere.co.uk

unread,
May 9, 2020, 6:44:19 AM5/9/20
to
On Sat, 9 May 2020 22:22:49 +1200
Ian Collins <ian-...@hotmail.com> wrote:
>On 09/05/2020 21:50, bol...@nowhere.co.uk wrote:
>> Hi
>>
>> Despite having worked with C++ for years I've never bothered with STL custom
>> allocators before. However now I need to. Using some code from various
>sources
>> I created a very simple custom allocator below which works perfectly in Clang
>
>> but not in 2 seperate versions of gcc which never call the allocate() or
>> deallocate() functions even though the code compiles fine. I'm sure I've made
>
>> some stupid error but I can't see what. Can anyone help?
>>
>> Many thanks
>
>Your code as posted won't compile (the string construction).

It compiles fine on 3 unix compilers. I'm guessing you're using VC++.

>In short, don't derive from std::allocator! Also, don't mix iostreams
>with C stdio.

There's nothing wrong with mixing iostreams with C stdio and there hasn't been
for years.



bol...@nowhere.co.uk

unread,
May 9, 2020, 6:47:31 AM5/9/20
to
On Sat, 9 May 2020 10:29:34 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>bol...@nowhere.co.uk wrote:
>> I created a very simple custom allocator below which works perfectly in Clang
>
>> but not in 2 seperate versions of gcc which never call the allocate() or
>> deallocate() functions even though the code compiles fine. I'm sure I've
>made
>> some stupid error but I can't see what. Can anyone help?
>
>The problem seems to be that you are inheriting from std::allocator.
>I'm not exactly sure why, but it may well be that the library
>implementation is doing some kind of shortcut if the allocator is
>of type std::allocator.
>
>You can fix it by not inheriting from std::allocator. Simply remove

Ok, but thats what every single code example does.

>that inheritance and add this to your class:
>
> using value_type = T;

What about in C++98?

>> printf("Pointer = %lu\n",(u_long)ptr);
>
>No such thing s "u_long". And you probably want to use "%p" for

Err, there very much is such a thing as u_long!

David Brown

unread,
May 9, 2020, 10:03:43 AM5/9/20
to
On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:

<snip>

>>
>> using value_type = T;
>
> What about in C++98?

What about it? It's a very long time since 1998. Why not use a more
modern C++ version?

>
>>> printf("Pointer = %lu\n",(u_long)ptr);
>>
>> No such thing s "u_long". And you probably want to use "%p" for
>
> Err, there very much is such a thing as u_long!
>

No, there isn't - not in standard C++. If you have a typedef for u_long
(a silly idea, IMHO, and certainly wrong in this case) then you have it
in /your/ program. But it is not a standard type and it needs a definition.

bol...@nowhere.co.uk

unread,
May 9, 2020, 11:05:42 AM5/9/20
to
On Sat, 9 May 2020 16:03:32 +0200
David Brown <david...@hesbynett.no> wrote:
>On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
>> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>
><snip>
>
>>>
>>> using value_type = T;
>>
>> What about in C++98?
>
>What about it? It's a very long time since 1998. Why not use a more
>modern C++ version?

Portability and curiosity. Allocators existed then so how was it done?
I presume a typedef since using = is just a wheel reinvention of the
same thing.

>> Err, there very much is such a thing as u_long!
>>
>
>No, there isn't - not in standard C++. If you have a typedef for u_long
>(a silly idea, IMHO, and certainly wrong in this case) then you have it
>in /your/ program. But it is not a standard type and it needs a definition.

Its defined in sys/types.h (or a file included from it) in the header files
of every unix compiler I've used. If VC++ doesn't have it then too bad but
then to be blunt a compiler that requires non standard nonsense such as
stdafx.h is in no position to dictate what is and isn't a silly idea.


Bo Persson

unread,
May 9, 2020, 11:55:00 AM5/9/20
to
The file stdafx.h is part of the support of precompiled headers, and
thus totally optional.

On the other hand I must have missed that unix system headers are now
part of the language. Care to point me at that C++ standard paragraph?


Bo Persson

David Brown

unread,
May 9, 2020, 11:58:06 AM5/9/20
to
On 09/05/2020 17:05, bol...@nowhere.co.uk wrote:
> On Sat, 9 May 2020 16:03:32 +0200
> David Brown <david...@hesbynett.no> wrote:
>> On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
>>> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
>>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>
>> <snip>
>>
>>>>
>>>> using value_type = T;
>>>
>>> What about in C++98?
>>
>> What about it? It's a very long time since 1998. Why not use a more
>> modern C++ version?
>
> Portability and curiosity. Allocators existed then so how was it done?

Portability should not be an issue - how many people will be using your
code without access to at least C++11 ? As for curiosity - often in
C++, this means "how painful was it to use the old language compared to
the newer and easier ways?".

> I presume a typedef since using = is just a wheel reinvention of the
> same thing.
>

I guess so. "Using" is more flexible and often clearer (IMHO) than
typedef, but in a case like this it should not be different.

>>> Err, there very much is such a thing as u_long!
>>>
>>
>> No, there isn't - not in standard C++. If you have a typedef for u_long
>> (a silly idea, IMHO, and certainly wrong in this case) then you have it
>> in /your/ program. But it is not a standard type and it needs a definition.
>
> Its defined in sys/types.h (or a file included from it) in the header files
> of every unix compiler I've used. If VC++ doesn't have it then too bad but
> then to be blunt a compiler that requires non standard nonsense such as
> stdafx.h is in no position to dictate what is and isn't a silly idea.
>

I haven't the slightest thought for VC++, which I have never used - and
I am equally against any VC++ or MS header specific and unnecessary
types. (I believe some of the MSVC++ headers have lots of silly type defs.)

If you have an unsigned long, the name of the type in C++ is "unsigned
long". There is rarely any advantage of have a typedef that gives you
nothing else (as distinct from typedefs like uint64_t) - possibly there
are situations where it is convenient for the type name to be a single
word. This is not such a case.

It may be the case that "u_long" is defined in sys/types.h in every *nix
toolchain /you/ have used (and it is defined on my Linux system). But
it is not standard C++, and not even standard POSIX. It is not
necessarily defined in other systems (C++ is used on far more than just
Unix and Windows). And your code does not include <sys/types.h>.

The appropriate choice of type for printf for a pointer is "%p" and type
"void*". If you really want to cast a pointer to an integer type, the
type to use is "uintptr_t" - that type /is/ standard, and will be
available on any C++ compiler (in theory it requires C++11, in practice
any C++ compiler), and it will be the correct size for pointers -
something that does not always apply to "unsigned long".





bol...@nowhere.co.uk

unread,
May 9, 2020, 12:17:08 PM5/9/20
to
An earlier poster stated there was no such thing as u_long. Its a standard
posix typedef. I'm not going to stick to "pure" c++ when I'm writing unix
code even if its test code, otherwise I'd have to throw process control,
networking and half a dozen other subsystems which "pure" c++ doesn't support
out the window.

Any more stupid questions?

bol...@nowhere.co.uk

unread,
May 9, 2020, 12:23:30 PM5/9/20
to
On Sat, 9 May 2020 17:57:57 +0200
David Brown <david...@hesbynett.no> wrote:
>On 09/05/2020 17:05, bol...@nowhere.co.uk wrote:
>> On Sat, 9 May 2020 16:03:32 +0200
>> David Brown <david...@hesbynett.no> wrote:
>>> On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
>>>> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
>>>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>
>>> <snip>
>>>
>>>>>
>>>>> using value_type = T;
>>>>
>>>> What about in C++98?
>>>
>>> What about it? It's a very long time since 1998. Why not use a more
>>> modern C++ version?
>>
>> Portability and curiosity. Allocators existed then so how was it done?
>
>Portability should not be an issue - how many people will be using your
>code without access to at least C++11 ? As for curiosity - often in

Plenty of old systems in companies have old compilers. A company I worked for
until 2019 was still on C++ 2003. Calls to upgrade fell on deaf ears.

>If you have an unsigned long, the name of the type in C++ is "unsigned
>long". There is rarely any advantage of have a typedef that gives you
>nothing else (as distinct from typedefs like uint64_t) - possibly there
>are situations where it is convenient for the type name to be a single
>word. This is not such a case.

Each to their own. unsigned long is long winded, u_long is short and to the
point and standard on unix.

>necessarily defined in other systems (C++ is used on far more than just
>Unix and Windows). And your code does not include <sys/types.h>.

It doesn't need to - its included by stdlib.h

>The appropriate choice of type for printf for a pointer is "%p" and type
>"void*". If you really want to cast a pointer to an integer type, the
>type to use is "uintptr_t" - that type /is/ standard, and will be
>available on any C++ compiler (in theory it requires C++11, in practice
>any C++ compiler), and it will be the correct size for pointers -
>something that does not always apply to "unsigned long".

Give somes example architectures when it wouldn't apply?

Ben Bacarisse

unread,
May 9, 2020, 3:30:35 PM5/9/20
to
64-bit MS Windows systems usually have a 32-bit long.

--
Ben.

Christian Gollwitzer

unread,
May 9, 2020, 3:50:58 PM5/9/20
to
Am 09.05.20 um 18:23 schrieb bol...@nowhere.co.uk:
>> The appropriate choice of type for printf for a pointer is "%p" and type
>> "void*". If you really want to cast a pointer to an integer type, the
>> type to use is "uintptr_t" - that type /is/ standard, and will be
>> available on any C++ compiler (in theory it requires C++11, in practice
>> any C++ compiler), and it will be the correct size for pointers -
>> something that does not always apply to "unsigned long".
>
> Give somes example architectures when it wouldn't apply?

The most famous is 64 bit Windows. Pointers are 64 bit - as expected -
but long is 32 bit. So casting a pointer to unsigned long looses half of
the information.

https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models

Christian

Keith Thompson

unread,
May 9, 2020, 5:17:59 PM5/9/20
to
bol...@nowhere.co.uk writes:
> On Sat, 9 May 2020 17:54:49 +0200
> Bo Persson <b...@bo-persson.se> wrote:
>>On 2020-05-09 at 17:05, bol...@nowhere.co.uk wrote:
>>> On Sat, 9 May 2020 16:03:32 +0200
>>> David Brown <david...@hesbynett.no> wrote:
>>>> On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
[...]
>>>>> Err, there very much is such a thing as u_long!
>>>>
>>>> No, there isn't - not in standard C++. If you have a typedef for u_long
>>>> (a silly idea, IMHO, and certainly wrong in this case) then you have it
>>>> in /your/ program. But it is not a standard type and it needs a definition.
>>>
>>> Its defined in sys/types.h (or a file included from it) in the header files
>>> of every unix compiler I've used. If VC++ doesn't have it then too bad but
>>> then to be blunt a compiler that requires non standard nonsense such as
>>> stdafx.h is in no position to dictate what is and isn't a silly idea.
>>
>>The file stdafx.h is part of the support of precompiled headers, and
>>thus totally optional.
>>
>>On the other hand I must have missed that unix system headers are now
>>part of the language. Care to point me at that C++ standard paragraph?
>
> An earlier poster stated there was no such thing as u_long.

There is no such thing in standard C++ (unless you define it yourself).
Saying there is no such thing is at worst slightly imprecise.

> Its a standard
> posix typedef.

Then you should be able to cite where POSIX specifies it. (I just
checked. It doesn't.)

Yes, it's defined in <sys/types.h> on some systems. On my Ubuntu
system, I see this in /usr/include/bits/types.h :

/* Convenience types. */
typedef unsigned char __u_char;
typedef unsigned short int __u_short;
typedef unsigned int __u_int;
typedef unsigned long int __u_long;

and <sys/types.h> defines, among other things:

typedef __u_long u_long;

Personally, I fail to see what's convenient about them. "unsigned long"
is a standard type and is completely portable to any conforming C++ (or
C) implementation. Using the name "u_long" adds no information. If
it's defined as "unsigned long" it's not useful. If it's defined as
some other type it's misleading.

(I'm mildly curious why those headers define those typedefs. There are
probably historical reasons.)

Typedefs that provide some information about how a type is used and/or
that can be defined differently on different implementations (like
size_t and time_t, for example) are useful. Typedefs that simply
provide shorter names for existing types are not, in my opinion.

> I'm not going to stick to "pure" c++ when I'm writing unix
> code even if its test code, otherwise I'd have to throw process control,
> networking and half a dozen other subsystems which "pure" c++ doesn't support
> out the window.

Sure, you can write gratuitously non-portable code if you like. Nobody
will stop you. But you can expect criticism for it.

To be clear, I don't object at all to using non-portable constructs in
non-portable code *if there's a valid reason for it*.

Do you have some reason to prefer writing "u_long" over "unsigned long"?

> Any more stupid questions?

Be less rude.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Ian Collins

unread,
May 9, 2020, 5:21:13 PM5/9/20
to
They weren't here. I'm happy the that bit of advice is generally valid.
The nonsense arguments that followed about format specifiers would
have been avoided if he'd just use iostreams!

--
Ian

Ian Collins

unread,
May 9, 2020, 5:26:40 PM5/9/20
to
On 09/05/2020 22:44, bol...@nowhere.co.uk wrote:
> On Sat, 9 May 2020 22:22:49 +1200
> Ian Collins <ian-...@hotmail.com> wrote:
>> On 09/05/2020 21:50, bol...@nowhere.co.uk wrote:
>>> Hi
>>>
>>> Despite having worked with C++ for years I've never bothered with STL custom
>>> allocators before. However now I need to. Using some code from various
>> sources
>>> I created a very simple custom allocator below which works perfectly in Clang
>>
>>> but not in 2 seperate versions of gcc which never call the allocate() or
>>> deallocate() functions even though the code compiles fine. I'm sure I've made
>>
>>> some stupid error but I can't see what. Can anyone help?
>>>
>>> Many thanks
>>
>> Your code as posted won't compile (the string construction).
>
> It compiles fine on 3 unix compilers. I'm guessing you're using VC++.

It needed -std=c++17 to compile with gcc and clang. I don't use windows.

>> In short, don't derive from std::allocator! Also, don't mix iostreams
>> with C stdio.
>
> There's nothing wrong with mixing iostreams with C stdio and there hasn't been
> for years.

If, as Juha pointed out, they are synchronised.

--
Ian.

Juha Nieminen

unread,
May 10, 2020, 1:52:33 AM5/10/20
to
bol...@nowhere.co.uk wrote:
>> using value_type = T;
>
> What about in C++98?

typedef T value_type;

Juha Nieminen

unread,
May 10, 2020, 1:55:06 AM5/10/20
to
bol...@nowhere.co.uk wrote:
> An earlier poster stated there was no such thing as u_long. Its a standard
> posix typedef. I'm not going to stick to "pure" c++ when I'm writing unix
> code even if its test code, otherwise I'd have to throw process control,
> networking and half a dozen other subsystems which "pure" c++ doesn't support
> out the window.

When you post code here, make sure it actually compiles. Your code
did not compile for me because of that "u_long".

Juha Nieminen

unread,
May 10, 2020, 2:01:33 AM5/10/20
to
bol...@nowhere.co.uk wrote:
> Each to their own. unsigned long is long winded

So? What's your point?

> u_long is short and to the point and standard on unix.

Why deliberately restrict your code to a single environment when
with an extremely small change you can make it more portable?
It makes no sense.

I find it quite ironic that you want your code to be C++98 conforming
to increase support for older compilers used in older systems... but
then you don't care that your code is unix-only.

bol...@nowhere.co.uk

unread,
May 10, 2020, 4:33:32 AM5/10/20
to
On Sat, 9 May 2020 21:50:47 +0200
Christian Gollwitzer <auri...@gmx.de> wrote:
>Am 09.05.20 um 18:23 schrieb bol...@nowhere.co.uk:
>>> The appropriate choice of type for printf for a pointer is "%p" and type
>>> "void*". If you really want to cast a pointer to an integer type, the
>>> type to use is "uintptr_t" - that type /is/ standard, and will be
>>> available on any C++ compiler (in theory it requires C++11, in practice
>>> any C++ compiler), and it will be the correct size for pointers -
>>> something that does not always apply to "unsigned long".
>>
>> Give somes example architectures when it wouldn't apply?
>
>The most famous is 64 bit Windows. Pointers are 64 bit - as expected -
>but long is 32 bit. So casting a pointer to unsigned long looses half of
>the information.

Ok, I didn't know that. It just proves to me yet again what a joke
that operating system and its tools are.

bol...@nowhere.co.uk

unread,
May 10, 2020, 4:35:45 AM5/10/20
to
On Sun, 10 May 2020 06:01:25 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>bol...@nowhere.co.uk wrote:
>> Each to their own. unsigned long is long winded
>
>So? What's your point?

That is the point. Unless you think all longs should
have been specified as "signed long" just to make it
clearer?

>
>> u_long is short and to the point and standard on unix.
>
>Why deliberately restrict your code to a single environment when
>with an extremely small change you can make it more portable?
>It makes no sense.

I don't code for Windows. If it doesn't compile on it I couldn't
care less nor do I have any way to test whether it does even if
I did care.

bol...@nowhere.co.uk

unread,
May 10, 2020, 4:42:07 AM5/10/20
to
On Sat, 09 May 2020 14:17:48 -0700
Keith Thompson <Keith.S.T...@gmail.com> wrote:
>bol...@nowhere.co.uk writes:
> typedef __u_long u_long;
>
>Personally, I fail to see what's convenient about them. "unsigned long"

So presumable you'd prefer to have to type "signed long" or "signed int"
instead of long or int then too?

>C) implementation. Using the name "u_long" adds no information. If

Using ++i adds no information over i = i + 1. Whats your point?

>(I'm mildly curious why those headers define those typedefs. There are
>probably historical reasons.)

I imagine people found them useful.

>Typedefs that provide some information about how a type is used and/or
>that can be defined differently on different implementations (like
>size_t and time_t, for example) are useful. Typedefs that simply
>provide shorter names for existing types are not, in my opinion.

That is indeed your opinion. Other peoples opinions differ.

>Sure, you can write gratuitously non-portable code if you like. Nobody

Well it compiled on 2 versions of gcc on 2 different linux distros
and on MacOS Mojave and Catalina. Thats portable enough for me. If it doesn't
compile on VC++ thats too bad, I can neither test for that nor do I give
a damn frankly.

>Do you have some reason to prefer writing "u_long" over "unsigned long"?

Presumably you write i = i + 1 instead of using pre/postfix increment
operators. Otherwise you wouldn't ask such a stupid question.

>> Any more stupid questions?
>
>Be less rude.

I'll pose that question again.


Bonita Montero

unread,
May 10, 2020, 5:00:06 AM5/10/20
to
Some time ago I wrote an allocator that maps either to mmap()
(POSIX) or VirtualAloc() (Windows). It is compatible wit compilers
before C++2017 and since C++2017.
Unfortunately I found that the allocator was used via typename
allocator_traits<myalloc>::template rebind_alloc<T> by std::vector
but I thought that it would be only used for a single allocation
by std::vector. So it wasn't usable for me anymore. But here's
the code:


#ifdef _MSC_VER
#include <Windows.h>
#elif __unix__
#include <sys/mman.h>
#endif
#include <cstddef>
#include <exception>
#include <cassert>
#include <new>
#include <memory>

#include <iostream>

template<class T>
class virtual_allocator
{
public:
typedef T value_type;
#if __cplusplus < 201703L
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
#endif
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
#if __cplusplus < 201703L
template<typename U>
struct rebind
{
typedef virtual_allocator<U> other;
};
#endif

explicit virtual_allocator() = default;
explicit virtual_allocator( virtual_allocator const &other
) = default;
template<typename U>
virtual_allocator( virtual_allocator<U> const
&other );
#if __cplusplus < 201703L
static pointer address( reference value );
static const_pointer address( const_reference value );
static size_type max_size() throw();
#endif
#if __cplusplus >= 201703L
T *allocate( size_type n, void *hint = nullptr );
void deallocate( T *p, size_type num = 1 );
#else
pointer allocate( size_type n, void *hint = nullptr );
void deallocate( pointer p, size_type num = 1 );
#endif
#if __cplusplus < 201703L
static void construct( pointer p, const T&value );
template<typename U>
static void destroy( U *p );
#endif
};

template<typename T>
template<typename U>
inline
virtual_allocator<T>::virtual_allocator( virtual_allocator<U> const
&other ) :
virtual_allocator()
{
}

#if __cplusplus < 201703L
template<typename T>
inline
typename virtual_allocator<T>::pointer virtual_allocator<T>::address(
reference value )
{
return &value;
}

template<typename T>
inline
typename virtual_allocator<T>::const_pointer
virtual_allocator<T>::address( const_reference value )
{
return &value;
}

template<typename T>
inline
typename virtual_allocator<T>::size_type
virtual_allocator<T>::max_size() throw()
{
return (size_t)(ptrdiff_t)-1 / sizeof(T);
}
#endif

template<typename T>
#if __cplusplus >= 201703L
T *virtual_allocator<T>::allocate( size_type n, void *hint )
#else
typename virtual_allocator<T>::pointer virtual_allocator<T>::allocate(
size_type n, void *hint )
#endif
{
std::cout << "allocate" << n << std::endl;
#if defined(_MSC_VER)
T *p = (T *)VirtualAlloc( hint, n * sizeof(T), MEM_RESERVE |
MEM_COMMIT, PAGE_READWRITE );
if( !p )
throw std::bad_alloc();
return p;
#elif __unix__
void *p = mmap( hint, n * sizeof(T), PROT_READ | PROT_WRITE, MAP_SHARED
| MAP_ANONYMOUS, -1, 0 );
if( p == MAP_FAILED )
throw std::bad_alloc();
return (pointer)p;
#else
#error no implementation for your OS
#endif
}

template<typename T>
#if __cplusplus >= 201703L
inline
void virtual_allocator<T>::deallocate( T *p, size_type n )
#else
inline
void virtual_allocator<T>::deallocate( pointer p, size_type n )
#endif
{
std::cout << "dellocate " << n << std::endl;
#if defined(_MSC_VER)
BOOL ret = VirtualFree( p, 0, MEM_RELEASE );
assert(ret);
#elif __unix__
int ret = munmap( p, n * sizeof(T) );
assert(ret == 0);
#else
#error no implementation for your OS
#endif
}

#if __cplusplus < 201703L
template<typename T>
inline
void virtual_allocator<T>::construct( pointer p, const T&value )
{
new( (void*)p ) T( value );
}

template<typename T>
template<typename U>
inline
void virtual_allocator<T>::destroy( U *p )
{
p->~T();
}
#endif

template<typename T, typename U>
inline
bool operator ==( virtual_allocator<T> &, virtual_allocator<U> & )
{
return true;
}

template<typename T, typename U>
inline
bool operator !=( virtual_allocator<T> &, virtual_allocator<U> & )
{
return false;
}

Maybe that's a skeleton for you to fill with your own allocator-code.

Jorgen Grahn

unread,
May 10, 2020, 5:41:16 AM5/10/20
to
For the record, I reason the same way. A lot of C++ code, probably
most and certainly mine, is not intended to be compiled on Windows.

Still, it's not pedagogical to include unnecessary Unixisms with
questions to comp.lang.c++ because everyone will comment on it and it
will draw attention away from the actual question.

Re: the actual question, I have no clue. Sorry. I've never used
custom allocators; they seem painful and useful only in rare
circumstances.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Keith Thompson

unread,
May 10, 2020, 5:45:37 AM5/10/20
to
Bye.

David Brown

unread,
May 10, 2020, 6:28:26 AM5/10/20
to
On 09/05/2020 18:23, bol...@nowhere.co.uk wrote:
> On Sat, 9 May 2020 17:57:57 +0200
> David Brown <david...@hesbynett.no> wrote:
>> On 09/05/2020 17:05, bol...@nowhere.co.uk wrote:
>>> On Sat, 9 May 2020 16:03:32 +0200
>>> David Brown <david...@hesbynett.no> wrote:
>>>> On 09/05/2020 12:47, bol...@nowhere.co.uk wrote:
>>>>> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
>>>>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>>
>>>> <snip>
>>>>
>>>>>>
>>>>>> using value_type = T;
>>>>>
>>>>> What about in C++98?
>>>>
>>>> What about it? It's a very long time since 1998. Why not use a more
>>>> modern C++ version?
>>>
>>> Portability and curiosity. Allocators existed then so how was it done?
>>
>> Portability should not be an issue - how many people will be using your
>> code without access to at least C++11 ? As for curiosity - often in
>
> Plenty of old systems in companies have old compilers. A company I worked for
> until 2019 was still on C++ 2003. Calls to upgrade fell on deaf ears.

Are you writing code for them? If not, why do you care? C++11 is a
better language than C++03 - it lets you write better code. I can
understand using an older standard if you have to, but not for new code
written by choice.

>
>> If you have an unsigned long, the name of the type in C++ is "unsigned
>> long". There is rarely any advantage of have a typedef that gives you
>> nothing else (as distinct from typedefs like uint64_t) - possibly there
>> are situations where it is convenient for the type name to be a single
>> word. This is not such a case.
>
> Each to their own. unsigned long is long winded, u_long is short and to the
> point and standard on unix.
>

It is not "standard" - common on *nix, but not standard (neither POSIX
not C++ standard). In fact, it is a non-conformity if it is defined as
a result of standard headers (like <stdlib.h>). (gcc and glibc are not
standards conforming by default.) In a brief test on gcc/glibc (various
versions on my Linux system), an include of <stdlib.h> gives the u_long
typedef for different C++ standard but not for the stricter conforming C
standards (it is defined for -std=gnu99 but not for -std=c99). It is
fine to have it defined for C++ -std=gnu++03, but it is a conformity
failure to have it defined for -std=c++03.

It is fine to use short forms when they are useful - that is one of the
reasons why C and C++ have typedefs, macros, include files, and all the
rest. But it is not a good idea to use pointless unnecessary
non-standard abbreviations in code posted for others to see.

If you find you are needing "unsigned long" a lot in your code, and want
to write "u_long" instead, that's fine. (I'd prefer to give a name that
reflects the use or purpose of the type.) I have lots of such cases in
my own code, and I'm sure many others do too. But when I post code here
I use standard types whenever possible.


>> necessarily defined in other systems (C++ is used on far more than just
>> Unix and Windows). And your code does not include <sys/types.h>.
>
> It doesn't need to - its included by stdlib.h
>
>> The appropriate choice of type for printf for a pointer is "%p" and type
>> "void*". If you really want to cast a pointer to an integer type, the
>> type to use is "uintptr_t" - that type /is/ standard, and will be
>> available on any C++ compiler (in theory it requires C++11, in practice
>> any C++ compiler), and it will be the correct size for pointers -
>> something that does not always apply to "unsigned long".
>
> Give somes example architectures when it wouldn't apply?
>

Windows 64 is the obvious case - "long" is 32-bit, while pointers are
64-bit.

And in smaller 8-bit and 16-bit systems, "long" is 32-bit while pointers
are typically 16-bit. (And yes, people use C++ on these.)

Non-portable and system-specific code is fine - that's what most people
write most of the time. /Pointlessly/ non-portable code is, well,
pointless.




Bo Persson

unread,
May 10, 2020, 6:52:05 AM5/10/20
to
You mean unlike other systems where long and long long are the exact
same size?


Bo Persson

Juha Nieminen

unread,
May 10, 2020, 10:09:44 AM5/10/20
to
bol...@nowhere.co.uk wrote:
> On Sun, 10 May 2020 06:01:25 -0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>>bol...@nowhere.co.uk wrote:
>>> Each to their own. unsigned long is long winded
>>
>>So? What's your point?
>
> That is the point. Unless you think all longs should
> have been specified as "signed long" just to make it
> clearer?

*What* is the point? I don't get it.

What's with this obsession that beginners have with shorter code?

>>> u_long is short and to the point and standard on unix.
>>
>>Why deliberately restrict your code to a single environment when
>>with an extremely small change you can make it more portable?
>>It makes no sense.
>
> I don't code for Windows. If it doesn't compile on it I couldn't
> care less nor do I have any way to test whether it does even if
> I did care.

If you don't care about standards, why were you talking about
Posix earlier, then?

Either way, if you want people *here* to help you, you should post
code that actually compiles. Using non-standard code is a way to
make sure that it won't compile and people will be less helpful.

bol...@nowhere.co.uk

unread,
May 11, 2020, 4:45:10 AM5/11/20
to
On 10 May 2020 09:41:07 GMT
Jorgen Grahn <grahn...@snipabacken.se> wrote:
>On Sun, 2020-05-10, bol...@nowhere.co.uk wrote:
>> On Sun, 10 May 2020 06:01:25 -0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>bol...@nowhere.co.uk wrote:
>>>> Each to their own. unsigned long is long winded
>>>
>>>So? What's your point?
>>
>> That is the point. Unless you think all longs should
>> have been specified as "signed long" just to make it
>> clearer?
>>
>>>
>>>> u_long is short and to the point and standard on unix.
>>>
>>>Why deliberately restrict your code to a single environment when
>>>with an extremely small change you can make it more portable?
>>>It makes no sense.
>>
>> I don't code for Windows. If it doesn't compile on it I couldn't
>> care less nor do I have any way to test whether it does even if
>> I did care.
>
>For the record, I reason the same way. A lot of C++ code, probably
>most and certainly mine, is not intended to be compiled on Windows.
>
>Still, it's not pedagogical to include unnecessary Unixisms with
>questions to comp.lang.c++ because everyone will comment on it and it
>will draw attention away from the actual question.

Only pedants desperate to score points would comment on something so trivial
instead of the issue at hand.

> Re: the actual question, I have no clue. Sorry. I've never used
> custom allocators; they seem painful and useful only in rare
> circumstances.

Clang makes them easy , it turns out using them with gcc is a PITA. Oh well.

bol...@nowhere.co.uk

unread,
May 11, 2020, 4:45:27 AM5/11/20
to
On Sun, 10 May 2020 02:45:27 -0700
Keith Thompson <Keith.S.T...@gmail.com> wrote:
>bol...@nowhere.co.uk writes:
>> On Sat, 09 May 2020 14:17:48 -0700
>> Keith Thompson <Keith.S.T...@gmail.com> wrote:
>>>Do you have some reason to prefer writing "u_long" over "unsigned long"?
>>
>> Presumably you write i = i + 1 instead of using pre/postfix increment
>> operators. Otherwise you wouldn't ask such a stupid question.
>>
>>>> Any more stupid questions?
>>>
>>>Be less rude.
>>
>> I'll pose that question again.
>
>Bye.

I didn't think you'd be able to answer.

bol...@nowhere.co.uk

unread,
May 11, 2020, 4:47:01 AM5/11/20
to
On Sun, 10 May 2020 12:28:16 +0200
David Brown <david...@hesbynett.no> wrote:
>On 09/05/2020 18:23, bol...@nowhere.co.uk wrote:
>>> Portability should not be an issue - how many people will be using your
>>> code without access to at least C++11 ? As for curiosity - often in
>>
>> Plenty of old systems in companies have old compilers. A company I worked for
>
>> until 2019 was still on C++ 2003. Calls to upgrade fell on deaf ears.
>
>Are you writing code for them? If not, why do you care? C++11 is a

I care for the same reason I keep my C skills up to date - you never know
what a future job may require and I hedge my bets. I'm not going to turn down
work simply because they use an old version of C++.

>> Each to their own. unsigned long is long winded, u_long is short and to the
>> point and standard on unix.
>>
>
>It is not "standard" - common on *nix, but not standard (neither POSIX

De facto standard then.

bol...@nowhere.co.uk

unread,
May 11, 2020, 4:47:37 AM5/11/20
to
Long should always be the size of a CPU word. Long long is implementation
dependent. In a sane world anyway.

bol...@nowhere.co.uk

unread,
May 11, 2020, 4:48:48 AM5/11/20
to
On Sun, 10 May 2020 14:09:35 -0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
>bol...@nowhere.co.uk wrote:
>> On Sun, 10 May 2020 06:01:25 -0000 (UTC)
>> Juha Nieminen <nos...@thanks.invalid> wrote:
>>>bol...@nowhere.co.uk wrote:
>>>> Each to their own. unsigned long is long winded
>>>
>>>So? What's your point?
>>
>> That is the point. Unless you think all longs should
>> have been specified as "signed long" just to make it
>> clearer?
>
>*What* is the point? I don't get it.
>
>What's with this obsession that beginners have with shorter code?

Do try and improve your patronisation techniques. I think the dinosaurs were
using that one.

>Either way, if you want people *here* to help you, you should post
>code that actually compiles. Using non-standard code is a way to
>make sure that it won't compile and people will be less helpful.

As I've said, it compiled on 4 different systems. If thats not enough then
too bad.

Ian Collins

unread,
May 11, 2020, 4:57:17 AM5/11/20
to
There's no difference in this case between the two compilers (or any
other assuming the code meets the standard's requirements).

--
Ian.

bol...@nowhere.co.uk

unread,
May 11, 2020, 5:45:53 AM5/11/20
to
Apart from the code works in Clang but not gcc. And if I don't inherit from
allocator it doesn't even compile in gcc never mind work. So no, no difference
at all.

Ian Collins

unread,
May 11, 2020, 5:56:36 AM5/11/20
to
Because it meets the standard's requirements, your code with the three
changes I posted compiles and runs correctly with both clang and gcc.

Your original code fails on both.

--
Ian.

Bo Persson

unread,
May 11, 2020, 6:00:05 AM5/11/20
to
But the world isn't sane.

The type was named long because it was 32 bits already when an int was
only 16. And then we got long long for even larger values.

Then making long the same as long long isn't immediately obvious. What's
the advantage of changing it to be the same as something else we already
introduced?


bol...@nowhere.co.uk

unread,
May 11, 2020, 6:03:14 AM5/11/20
to
On Mon, 11 May 2020 21:56:23 +1200
Ian Collins <ian-...@hotmail.com> wrote:
>On 11/05/2020 21:45, bol...@nowhere.co.uk wrote:
>> On Mon, 11 May 2020 20:57:08 +1200
>> Ian Collins <ian-...@hotmail.com> wrote:
>>> On 11/05/2020 20:45, bol...@nowhere.co.uk wrote:
>>>> On 10 May 2020 09:41:07 GMT
>>>> Jorgen Grahn <grahn...@snipabacken.se> wrote:
>>>>
>>>>> Re: the actual question, I have no clue. Sorry. I've never used
>>>>> custom allocators; they seem painful and useful only in rare
>>>>> circumstances.
>>>>
>>>> Clang makes them easy , it turns out using them with gcc is a PITA. Oh
>well.
>>>
>>> There's no difference in this case between the two compilers (or any
>>> other assuming the code meets the standard's requirements).
>>
>> Apart from the code works in Clang but not gcc. And if I don't inherit from
>> allocator it doesn't even compile in gcc never mind work. So no, no
>difference
>> at all.
>
>Because it meets the standard's requirements, your code with the three
>changes I posted compiles and runs correctly with both clang and gcc.

You posted 2 changes, not 3 (unless you count your nonsense about not mixing
iostreams with stdio). And no, it doesn't compile on gcc never mind run. I
suggest you try it first next time.

David Brown

unread,
May 11, 2020, 6:18:27 AM5/11/20
to
Perhaps in your imagined world, those are the rules. Back here in the
world of real-life processors, C standards, and real-life platforms, the
rules are different.

"long" is at least 32-bit, and at least as big as "int". That is what
the C standards require. Usually it is either 32-bit or 64-bit, and
almost invariably 32-bit on 32-bit processors. For 64-bit processors,
it varies - some systems use 32-bit long, others 64-bit long. The
choice is generally made based on what reduces the work needed to move
code from 32-bit systems to 64-bit systems.

"long long" is at least 64-bit, and at least as big as "long". In
practice, that almost invariably means /exactly/ 64-bit. I have never
heard of a system that used anything else for "long long".

Both "long" and "long long" are implementation dependent.

If you make any assumptions about them other than what I wrote above,
you are wrong.

For those that want types for specific purposes, C99 brought in a range
of size-specific types (like uint32_t) and specific purpose types (like
uintptr_t). You'd be hard pushed to find a compiler that doesn't have
these available, even if you are using an older standard like C90 or C++98.


Personally, I don't see much use of "long" or "long long" in code.
Whenever these /might/ make sense, there are better types that specify
my needs more accurately. Other people might find them more useful.
But often their use is incorrect, or at least inappropriate and
needlessly non-portable.

Manfred

unread,
May 11, 2020, 6:19:43 AM5/11/20
to
Correction. That's the rationale for a plain 'int', not 'long'. On top
of this, historical reasons add up, obviously.

Manfred

unread,
May 11, 2020, 6:31:16 AM5/11/20
to
You should look at
https://en.cppreference.com/w/cpp/named_req/Allocator

Then you'll see that your allocator does not meet the requirements as
dictated by the standard - which have not been specified for the sole
purpose of annoying people.
So no, "it compiled on 4 different systems" is not enough.

"I tried it, it compiled and it worked" is a good recipe for failure in C++.

bol...@nowhere.co.uk

unread,
May 11, 2020, 6:55:59 AM5/11/20
to
I'll go out and buy a Windows machine with a copy of VC++ to test all further
example code I post to usenet just to keep you pedants happy. That good
enough?

Juha Nieminen

unread,
May 11, 2020, 11:43:47 AM5/11/20
to
bol...@nowhere.co.uk wrote:
>>Either way, if you want people *here* to help you, you should post
>>code that actually compiles. Using non-standard code is a way to
>>make sure that it won't compile and people will be less helpful.
>
> As I've said, it compiled on 4 different systems. If thats not enough then
> too bad.

Well, don't expect any more help from me, asshole.

Bonita Montero

unread,
May 11, 2020, 11:47:32 AM5/11/20
to
> Long should always be the size of a CPU word.
> Long long is implementation dependent. In a sane world anyway.

There are no rules that mandate either.

bol...@nowhere.co.uk

unread,
May 11, 2020, 11:56:32 AM5/11/20
to
Point out where you actually gave me some useful help and I might feel upset
about that - its still not working on gcc despite trying various suggestions
from here. And its ARSEhole unless you're talking about donkeys or you prefer
the american dialect.

Juha Nieminen

unread,
May 11, 2020, 2:27:22 PM5/11/20
to
bol...@nowhere.co.uk wrote:
> On Mon, 11 May 2020 15:43:31 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>>bol...@nowhere.co.uk wrote:
>>>>Either way, if you want people *here* to help you, you should post
>>>>code that actually compiles. Using non-standard code is a way to
>>>>make sure that it won't compile and people will be less helpful.
>>>
>>> As I've said, it compiled on 4 different systems. If thats not enough then
>>> too bad.
>>
>>Well, don't expect any more help from me, asshole.
>
> Point out where you actually gave me some useful help and I might feel upset
> about that - its still not working on gcc despite trying various suggestions
> from here.

But it works here, so I don't care. Right back at you.

Ian Collins

unread,
May 11, 2020, 4:42:27 PM5/11/20
to
Oh dear..

b.cc is your code with my suggested fixes, b-original.cc is your code as
posted:

$ diff b.cc b-original.cc
13c13
< class myallocator
---
> class myallocator: public allocator<T>
16,18c16
< using value_type = T;
<
< T *allocate(size_t cnt)
---
> T *allocate(size_t cnt, const void *hint=0)

If you look really carefully you will see three changes there.

$ g++ -std=c++11 b.cc && ./a.out
Creating vector...
Allocating 1 instances, 4 bytes
Pointer = 94319169221248
Allocating 2 instances, 8 bytes
Pointer = 94319169221280
Deallocating pointer 94319169221248
Allocating 4 instances, 16 bytes
Pointer = 94319169221248
Deallocating pointer 94319169221280
-----
Creating string...
Appending string...
Allocating 31 instances, 31 bytes
Pointer = 94319169221312
End
Deallocating pointer 94319169221312
Deallocating pointer 94319169221248

This appears to both compile and run.

--
Ian.
0 new messages