Saturday, May 9, 2020

Digest for comp.lang.c++@googlegroups.com - 25 updates in 4 topics

Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: May 09 01:55AM +0100

Hi!
 
Today I created a C++ recursive spinlock (based on the spinlock in Boost) and it seems to work! Spinlocks can be a lot faster than the mutexes supplied by the operating system.
 
https://github.com/i42output/neolib/blob/master/include/neolib/mutex.hpp
 
#cpp #gamedev #coding #neoGFX
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say."
Bonita Montero <Bonita.Montero@gmail.com>: May 09 09:49AM +0200

> Today I created a C++ recursive spinlock (based on the spinlock in
> Boost) and it seems to work! Spinlocks can be a lot faster than the
> mutexes supplied by the operating system.
 
Spinlocks don't make sense in userland because you can't disable
the scheduler in userland. The problem here is that a thread holding
a spinlock might get de-scheduled and other treads will spin and con-
sume CPU-time unutil it gets re-scheduled to relinquish the ownership.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: May 09 02:57PM -0700

On 5/9/2020 12:49 AM, Bonita Montero wrote:
> the scheduler in userland. The problem here is that a thread holding
> a spinlock might get de-scheduled and other treads will spin and con-
> sume CPU-time unutil it gets re-scheduled to relinquish the ownership.
 
Mostly true. However, an adaptive lock, that spins a couple of times
before it actually blocks can be useful in userland. The PAUSE
instruction can help out here.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: May 08 02:53PM -0700

On 5/8/2020 2:18 PM, Mr Flibble wrote:
> neoGFX achieves 944 FPS:
 
> https://camo.githubusercontent.com/d32e8fabf762b33adbf4f18f447f3530b9b66fd6/687474703a2f2f6e656f6766782e6f72672f74656d702f6c6f6c2e706e673f69643d31
 
> /Flibble
 
Try out a shader. Something like:
 
https://www.shadertoy.com/view/MdXSWn
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: May 09 02:54PM -0700

On 5/8/2020 4:23 PM, Mr Flibble wrote:
 
>> https://www.shadertoy.com/view/MdXSWn
 
> neoGFX already has a C++ shader architecture and most of its drawing
> primitives use shader code.
 
Okay, well... You are going to have to add a throttle. Say 60 fps is
perfect for a game. 944 fps would requite the gamer to smoke caffeine or
something. ;^)
boltar@nowhere.co.uk: May 09 09:50AM

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 <ian-news@hotmail.com>: May 09 10:22PM +1200

> 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.
 
 
> 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 <nospam@thanks.invalid>: May 09 10:29AM

> 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 <nospam@thanks.invalid>: May 09 10:31AM

> 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.
boltar@nowhere.co.uk: May 09 10:44AM

On Sat, 9 May 2020 22:22:49 +1200
 
>> 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.
boltar@nowhere.co.uk: May 09 10:47AM

On Sat, 9 May 2020 10:29:34 -0000 (UTC)
>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 <david.brown@hesbynett.no>: May 09 04:03PM +0200

> On Sat, 9 May 2020 10:29:34 -0000 (UTC)
> Juha Nieminen <nospam@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.
boltar@nowhere.co.uk: May 09 03:05PM

On Sat, 9 May 2020 16:03:32 +0200
 
>> 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.
 
 
>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 <bo@bo-persson.se>: May 09 05:54PM +0200

> 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?
 
 
Bo Persson
David Brown <david.brown@hesbynett.no>: May 09 05:57PM +0200


>> 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.
 
> 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".
boltar@nowhere.co.uk: May 09 04:16PM

On Sat, 9 May 2020 17:54:49 +0200
>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. 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?
boltar@nowhere.co.uk: May 09 04:23PM

On Sat, 9 May 2020 17:57:57 +0200
 
>> 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.
 
>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
 
>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 <ben.usenet@bsb.me.uk>: May 09 08:30PM +0100

>>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?
 
64-bit MS Windows systems usually have a 32-bit long.
 
--
Ben.
Christian Gollwitzer <auriocus@gmx.de>: May 09 09:50PM +0200

>> 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 <Keith.S.Thompson+u@gmail.com>: May 09 02:17PM -0700

>>> On Sat, 9 May 2020 16:03:32 +0200
>>> David Brown <david.brown@hesbynett.no> wrote:
>>>> On 09/05/2020 12:47, boltar@nowhere.co.uk wrote:
[...]
 
>>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.
 
> 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.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Ian Collins <ian-news@hotmail.com>: May 10 09:21AM +1200

On 09/05/2020 22:31, Juha Nieminen 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.
 
 
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 <ian-news@hotmail.com>: May 10 09:26AM +1200


>>> 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.
 
>> 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.
Tim Rentsch <tr.17687@z991.linuxsc.com>: May 09 03:22AM -0700


> This is some serious feature creep. Do you realize you have just
> casually invented a new not yet existing language, following a
> complicated set of rules mixed up from two existing languages?
 
I don't know why you think that's true. It's a simple rule, and
the semantics of C is well defined.
 
That said, I acknowledge some of the reservations expressed, and
would be happy to consider other ways of providing similar
functionality. The important thing is to be able to write an
interface that is sure to be understood the same way by both
a C compiler and a C++ compiler. How that is expressed is also
important, but secondary to having some way to get it done.
 
> It would need a 10-year language design and standardization effort
> to get it non-contradictory and useful, by which time both the
> target languages have already evolved away.
 
Is this hyperbole, or overreaction? Surely potential problems
could be identified and worked out within a normal 3-year C++
revision cycle. And C evolves more slowly than C++.
 
> Seriously guys, what have you got now with extern "C"? Can't you
> accept it's basically just an instruction to the linker, similar
> to inline'?
 
I understand -- now -- that it is viewed that way by some people
in the C++ community. Unfortunately a major use case -- perhaps
/the/ major use case? -- is to allow an interface header for C
code to be accepted and compiled by a C++ program, as well as by
C programs. Seen from that perspective, how 'extern "C"' works
now comes up short. Surely you at least admit that a major use
case for 'extern "C"' is to wrap an interface header for some C
code so that the C library can be used by a C++ program, right?
Tim Rentsch <tr.17687@z991.linuxsc.com>: May 09 03:56AM -0700


>> Seriously guys, what have you got now with extern "C"? Can't you accept
>> it's basically just an instruction to the linker, similar to 'inline'?
 
> It could be some other keyword [..eg..] _Pure "C".
 
Yes. There are advantages to keep using 'extern "C" { ... }' for
this purpose, but certainly there are also some costs so it is
reasonable to explore possible alternatives.
 
> But that would require C++ standard to specify by what C standard
> rules the _Pure "C" code is compiled
 
Undoubtedly that would be done by the C++ standard referencing
a specific version of the C standard, much like what is done
now (isn't it?) for C library calls and other connections to
standard C. Do you see any problems with that approach?
 
> and how the symbols in _Pure "C" block
> interact with symbols outside of it (if at all).
 
This is a good point. We would like to be sure that any
dependencies on any outside context have the same meaning when
compiled as C++ as they do when compiled as C. The easy first
idea is to allow an outside symbol to be used only if it were
also declared (or defined) inside a "take this as C" wrapper.
Of course, whatever rule is suggested, it's important to try
it out and get some experience with it before deciding which
rule is adopted.
Tim Rentsch <tr.17687@z991.linuxsc.com>: May 09 05:56AM -0700

> While interoperability at the level of function signatures
> (i.e. linkage) is definitely a must, I don't see much gain at the
> level of procedure body.
 
Probably it would help if I explain the experience that prompted
my suggestion.
 
Some time ago I wrote a small C library, more for fun than
anything else, that turned out to be more useful than I
originally expected. Naturally I had already written the .h
interface headers so the library could be used conveniently by
other C code. When I realized the library's greater usefulness
of course I set about modifying the library's headers files so it
would be callable from C++.
 
Doing that was more work than I expected. The extra work didn't
bother me, but something else came up that did. The interface
defines some inline functions. What I discovered is that the
rules for inline functions is different in C++ than it is in
C: even when an inline function definition is accepted in both
languages it doesn't always mean the same thing. Ultimately I
decided to remove all the inline function definitions because
there was no practical way to be sure how they would work in
C++ would be the same as how they work in C.
 
Since then I have discovered many more incompatibilities between
C and C++, including both ones that cause compilation errors and
ones that are accepted but have different meanings in the two
languages. (A recent comp.lang.c++ post I sent recently gives a
partial list of those.) When I first started programming in C++
(which was quite a while ago, even before the first C standard)
there was very little in C that wasn't exactly the same in C++.
Since then that has changed a lot, and to all indications will
only get larger as time goes on.
 
The extern "C" construct serves two related but distinct purposes.
One purpose is outcall, so C++ code can call functions defined in
C. The other purpose is incall, so C code can call functions
defined in C++. For incall, extern "C" works pretty well (at
least, so I gather). For outcall -- that is, for writing headers
that can be compiled either as C or as C++, so C functions can
be called either from C or from C++ -- how extern "C" works is
not nearly as useful as it is for incall, and even dangerous in
some respects. I hope people can understand that my proposal
is motivated by a desire to address some problems on the outcall
side, without meaning or wanting to adversely affect the other
uses.
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: