Friday, October 21, 2022

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

Manfred <noname@add.invalid>: Oct 21 05:52AM +0200

On 10/20/2022 8:21 PM, Lynn McGuire wrote:
> was 13 or 14.
 
> His actual comment was that static_cast's are easier to grep which I
> find hard to believe.
 
If by grep you mean grep(1), then yes, static_cast is definitely easier
to grep than a C-style cast.
However, the advantage of reinterpret_cast (static_cast wouldn't work)
is not that it is more readable. It is that it hurts the eye.
 
Depending on which compiler you use, I'd verify that what you intend to
do actually works. As far as the standard is concerned, at least one
necessary condition is that fem::str<8> is effectively an unsigned char[8].
Otherwise it's UB unless your compiler says otherwise (although it
probably Just Works on any of them, in practice.)
 
Bonita Montero <Bonita.Montero@gmail.com>: Oct 21 05:21PM +0200

Am 20.10.2022 um 17:32 schrieb JiiPee:
 
> sure, although about 99.9% in cases the speed is not an issue in these
> object oriented programs. But sure, if speed is in essence, one should
> consider not using it.
 
That's nonsense. OOP doesn't cost more than procedural programming since
with the latter you have context like this also. Virtual functions have
some slight overhead but it is very small.
Bonita Montero <Bonita.Montero@gmail.com>: Oct 21 05:24PM +0200

Am 20.10.2022 um 16:55 schrieb JiiPee:
>> that static_cast<fem::str<8>*> is more "readable". Heh.
 
> its surely not more readable.
> but dynamic_cast is surely useful checking class hierarkies.
 
A virtual function that gives some type-capabiliy information
is usually much faster.
Lynn McGuire <lynnmcguire5@gmail.com>: Oct 21 01:59PM -0500

On 10/20/2022 10:52 PM, Manfred wrote:
> probably Just Works on any of them, in practice.)
 
>> Thanks,
>> Lynn
 
I am using Visual Studio 2015 on Windows 10 Pro x64.
 
fem::str<8> is an array of unsigned char [8] that I pass around the
place to hold a Fortran string of given length that is blank filled
rather than null terminated.
https://cci.lbl.gov/fable/sources/fable/fem/str.hpp
 
And yes, I will be able to tell rather quickly if the cast is working
properly or not. I am minimizing usage though as I prefer char * and
std::string.
 
Thanks,
Lynn
Lynn McGuire <lynnmcguire5@gmail.com>: Oct 21 02:05PM -0500

On 10/20/2022 12:14 PM, JiiPee wrote:
> of cases against not using it. Talking about the slowness of static cast
> here. But of course I would not put a static cast in a tight loop
> looping millions of things a second.
 
I am always concerned about speed. My calculation engine needs to have
responses in seconds if needful for large online rotating equipment up
to 55,000 hp in size.
 
My other case is the endless recycle calculations of refinery or large
natural gas plants that can go 20 or 30 minute on a modern 4 Ghz cpu.
 
When we finish our C++ port then we will be looking at selected speedups
using limited parallelization and memset.
 
Lynn
JiiPee <kerrttuPoistaTama11@gmail.com>: Oct 22 12:09AM +0300

On 21/10/2022 22:05, Lynn McGuire wrote:
>> static cast here. But of course I would not put a static cast in a
>> tight loop looping millions of things a second.
 
> I am always concerned about speed.
 
IN my coding, also professional, very rarely this kind of thing would
slow down essentially. I have very rarely time critical situations.
olcott <none-ya@beez-waxes.com>: Oct 20 10:17PM -0500

On 10/17/2022 10:23 AM, Ben Bacarisse wrote:
> because..." was one way he used to put it before finding a more tricky
> wording. For years, the project has simply been to find words he can
> dupe people with.
 
I will keep posting this every day reminding people that Ben has agreed
that Sipser_H does correctly compute the halt status of Sipser_D
according to this criteria:
 
*Professor Sipser has agreed to these verbatim words* (and no more)
If simulating halt decider *H correctly simulates its input D until H*
*correctly determines that its simulated D would never stop running*
*unless aborted* then H can abort its simulation of D and correctly
report that D specifies a non-halting sequence of configurations.
 
until someone like Andre gives me an accurate review of this paper.
 
*Simulating Halt Decider Applied to the Halting Theorem*
https://www.researchgate.net/publication/364302709_Simulating_Halt_Decider_Applied_to_the_Halting_Theorem
 
 
--
Copyright 2022 Pete Olcott
 
"Talent hits a target no one else can hit;
Genius hits a target no one else can see."
Arthur Schopenhauer
olcott <polcott2@gmail.com>: Oct 21 03:03PM -0500

On 10/17/2022 10:23 AM, Ben Bacarisse wrote:
> one no one cares about. D(D) halts (so H is not halt decider), but D(D)
> would not halt unless H stops the simulation. H /can/ correctly
> determine this silly criterion (in this one case) so H is a POOH decider
 
Ben has agreed that Sipser_H does correctly compute the halt status of
Sipser_D according to this criteria:
 
*Professor Sipser has agreed to these verbatim words* (and no more)
If simulating halt decider *H correctly simulates its input D until H*
*correctly determines that its simulated D would never stop running*
*unless aborted* then H can abort its simulation of D and correctly
report that D specifies a non-halting sequence of configurations.
 
*Simulating Halt Decider Applied to the Halting Theorem*
https://www.researchgate.net/publication/364302709_Simulating_Halt_Decider_Applied_to_the_Halting_Theorem
 
 
>> The correct simulation is the correct simulation who ever does it, and
>> since D will halt when run, the correct simulation of D will halt.
 
> Right, but that's not the criterion that PO is using, is it? I don't
 
Ben agrees that Richard is evaluating my work using the wrong criteria.
 
*This is the criteria that I am using*
 
*Professor Sipser has agreed to these verbatim words* (and no more)
If simulating halt decider *H correctly simulates its input D until H*
*correctly determines that its simulated D would never stop running*
*unless aborted* then H can abort its simulation of D and correctly
report that D specifies a non-halting sequence of configurations.
 
> because..." was one way he used to put it before finding a more tricky
> wording. For years, the project has simply been to find words he can
> dupe people with.
 
Professor Sipser knows these things much deeper than my learned-by-rote
from a textbook reviewers.
 
 
 
--
Copyright 2022 Pete Olcott "Talent hits a target no one else can hit;
Genius hits a target no one else can see." Arthur Schopenhauer
Juha Nieminen <nospam@thanks.invalid>: Oct 21 11:44AM

(I don't know if this applies to other compilers like clang. Could be.)
 
For the longest time I thought that if gcc sees a function implementation
at the place where the function is being called, then it doesn't matter
if the keyword 'inline' appears before that function implementation or
not. I thought that gcc just ignores that keyword when making inlining
decisions. (After all, why wouldn't it?)
 
Just now, however, I got a concrete counter-example to this.
 
I had a number-crunching class declared and implemented locally in a
a source file (ie. inside a nameless namespace). While I separated
the class definition from the function implementations, I didn't use
any 'inline' keywords.
 
After a while, when the class grew a bit too large, I decided to move its
function implementations to another source file and, thus, make the class
global (well, inside a namespace, but still global). I figured that this
wouldn't affect its speed because all the number-cruching happened
inside the class, with its function calling other functions of the
same class.
 
To my puzzlement, the class became almost twice as slow. To my logic it
shouldn't have, because all the function implementations were visible
where they needed to be as fast as possible.
 
After wondering about it for a while I decided to try to add the 'inline'
keyword in front of all the function implementations (except the couple
that were called from the outside).
 
And what do you know, the class became as fast as before.
 
So it appears that I have been wrong: When it comes to functions visible
at the global scope, the 'inline' keyword can make a huge difference,
even when the implementations are seen by the compiler at the call
places.
 
It appears that gcc uses a different inlining strategy when dealing
with local and global functions (that have no 'inline' keyword).
Michael S <already5chosen@yahoo.com>: Oct 21 07:01AM -0700

On Friday, October 21, 2022 at 2:44:59 PM UTC+3, Juha Nieminen wrote:
> places.
 
> It appears that gcc uses a different inlining strategy when dealing
> with local and global functions (that have no 'inline' keyword).
 
Did you compare which functions were inlined before and after the change?
Is it possible that the function(s) that made the difference for performance
are called once?
Assuming -O2, the 'static' function (static in C sense rather in C++ sense) will
be inlined even when it does not pass other heuristics, most importantly
the size heuristics.
I recommend to read this section of the manual:
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Optimize-Options.html#Optimize-Options
It would not make things clear, because the matter is *not* simple, but
hopefully it will give you better look.
In particular, read about -finline-functions-called-once and -finline-limit.
 
If your program is not big or release builds are not frequent, you can try -flto.
It reduces difference between local and global things.
Bo Persson <bo@bo-persson.se>: Oct 21 04:41PM +0200

On 2022-10-21 at 13:44, Juha Nieminen wrote:
> at the global scope, the 'inline' keyword can make a huge difference,
> even when the implementations are seen by the compiler at the call
> places.
 
It probably doesn't make a huge difference in general, but if your
function is 'close' to getting inlined, an actual 'inline' keyword might
add a few points to the heuristics, and tip it over the decision point.
Andrey Tarasevich <andreytarasevich@hotmail.com>: Oct 21 08:47AM -0700

On 10/21/2022 4:44 AM, Juha Nieminen wrote:
> if the keyword 'inline' appears before that function implementation or
> not. I thought that gcc just ignores that keyword when making inlining
> decisions. (After all, why wouldn't it?)
 
GCC's behavior in this regard is difficult to predict and it seems to be
rather fluid.
 
I can easily provide an example for you in which GCC will honor `inline`
keyword when making decisions about inlining a call
 
#include <iostream>
 
void hello()
{
std::cout << "Hello World" << std::endl;
}
 
int main()
{
hello();
}
 
GCC refuses to inline the `hello()` call even in -O3 mode. But if you
add the `inline` keyword to the declaration of `hello()`, the call will
be inlined starting from -O1.
 
However, make two calls to `hello()` from `main()`
 
int main()
{
hello();
hello();
}
 
and the calls will not be inlined even if you slap `static inline` onto
`hello()`.
 
--
Best regards,
Andrey.
scott@slp53.sl.home (Scott Lurndal): Oct 21 04:04PM

> }
 
>and the calls will not be inlined even if you slap `static inline` onto
>`hello()`.
 
That's because of the awful iostream crap.
 
This version inlines both calls:
 
$ cat /tmp/c.cpp
#include <stdio.h>
 
inline void hello()
{
printf("Hello World\n");
}
 
int main()
{
hello();
hello();
}
 
0000000000400500 <main>:
400500: 48 83 ec 08 sub $0x8,%rsp
400504: bf a0 06 40 00 mov $0x4006a0,%edi
400509: e8 d2 ff ff ff callq 4004e0 <puts@plt>
40050e: bf a0 06 40 00 mov $0x4006a0,%edi
400513: e8 c8 ff ff ff callq 4004e0 <puts@plt>
400518: 31 c0 xor %eax,%eax
40051a: 48 83 c4 08 add $0x8,%rsp
40051e: c3 retq
40051f: 90 nop
 
As opposed to the iostream version, which it doesn't make sense to inline.
 
0000000000400990 <hello()>:
400990: 53 push %rbx
400991: ba 0b 00 00 00 mov $0xb,%edx
400996: be 90 0a 40 00 mov $0x400a90,%esi
40099b: bf 80 10 60 00 mov $0x601080,%edi
4009a0: e8 7b fe ff ff callq 400820 <std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)@plt>
4009a5: 48 8b 05 d4 06 20 00 mov 0x2006d4(%rip),%rax # 601080 <std::cout@@GLIBCXX_3.4>
4009ac: 48 8b 40 e8 mov -0x18(%rax),%rax
4009b0: 48 8b 98 70 11 60 00 mov 0x601170(%rax),%rbx
4009b7: 48 85 db test %rbx,%rbx
4009ba: 74 3c je 4009f8 <hello()+0x68>
4009bc: 80 7b 38 00 cmpb $0x0,0x38(%rbx)
4009c0: 74 1e je 4009e0 <hello()+0x50>
4009c2: 0f b6 43 43 movzbl 0x43(%rbx),%eax
4009c6: bf 80 10 60 00 mov $0x601080,%edi
4009cb: 0f be f0 movsbl %al,%esi
4009ce: e8 6d fe ff ff callq 400840 <std::ostream::put(char)@plt>
4009d3: 5b pop %rbx
4009d4: 48 89 c7 mov %rax,%rdi
4009d7: e9 54 fe ff ff jmpq 400830 <std::ostream::flush()@plt>
4009dc: 0f 1f 40 00 nopl 0x0(%rax)
4009e0: 48 89 df mov %rbx,%rdi
4009e3: e8 e8 fd ff ff callq 4007d0 <std::ctype<char>::_M_widen_init() const@plt>
4009e8: 48 8b 03 mov (%rbx),%rax
4009eb: be 0a 00 00 00 mov $0xa,%esi
4009f0: 48 89 df mov %rbx,%rdi
4009f3: ff 50 30 callq *0x30(%rax)
4009f6: eb ce jmp 4009c6 <hello()+0x36>
4009f8: e8 b3 fd ff ff callq 4007b0 <std::__throw_bad_cast()@plt>
4009fd: 0f 1f 00 nopl (%rax)
Aaron Gray <aaronngray@gmail.com>: Oct 20 11:35PM -0700

I have been trying to get an is() and as() functions working and as theres no dynamic is_subclass in C++ I have resulted in going back to relying on dynamic_cast !!! I cannot seem to get inbuilt ints to work though.
 
#include <iostream>
#include <type_traits>
 
template <typename T>
std::string typeof() { in
return typeid(T).name();
}
 
template <typename T>
std::string typeof(T t) {
return typeid(t).name();
}
 
template <typename T, typename V>
bool is(V* t) {
try {
return dynamic_cast<T*>(t) != nullptr;
}
catch (std::bad_cast) {
return false;
}
}
 
template <typename T, typename V>
bool is(V& t) {
try {
dynamic_cast<T&>(t);
return true;
}
catch (std::bad_cast) {
return false;
}
}
template <> // FAILING !
bool is<int&>(int t) {
return true;
}
 
template <typename T, typename V>
T& as(V t) {
return *dynamic_cast<T*>(&t);
}
template <typename T, typename V>
T* as(V* t) {
return dynamic_cast<T*>(t);
}
 
class Z {
public:
virtual void f() {};
};
class X : public Z {
public:
virtual void f() {};
};
class Y : public X {
public:
virtual void f() {};
};
class U {
public:
virtual void f() {};
};
class V : public U {
virtual void f() {};
};
 
int main() {
int i = 4;
int& i2 = i;
X x;
Y y;
V v;
X* x2 = &y;
X& x3 = y;
 
std::cout << typeof<X>() << std::endl;
std::cout << typeof<X>() << std::endl;
std::cout << typeof(x) << std::endl;
std::cout << typeof(y) << std::endl;
// std::cout << typeof<int&>() << std::endl; // needs intergral type template specialization case
// std::cout << typeof(i2) << std::endl;
 
std::cout << is<X>(x) << std::endl;
std::cout << is<X>(y) << std::endl;
std::cout << is<int&>(i) << std::endl; //fail
std::cout << is<int&>(i2) << std::endl; // fail
 
std::cout << is<Y>(x) << std::endl;
std::cout << is<X>(v) << std::endl;
std::cout << is<Y>(x2) << std::endl;
std::cout << is<Y>(x3) << std::endl; // reference upcasts pass !
 
//std::cout << typeid(X). << std::endl;
}
Andrey Tarasevich <andreytarasevich@hotmail.com>: Oct 21 01:45AM -0700

On 10/20/2022 11:35 PM, Aaron Gray wrote:
> bool is<int&>(int t) {
> return true;
> }
 
You are using a template specialization syntax, but your specialization
does not match any of the previously declared "main" templates. So far
you declared two "main" templates: one that takes a pointer and one that
takes a reference. The specialization takes an `int`, which does not
match any of the "main" templates.
 
This will work
 
template <typename T>
bool is(int t){
return false;
}
 
template <> bool is<int&>(int t) {
return true;
}
 
Whether it is the best way to go about implementing your intent is a
different question...
 
--
Best regards,
Andrey.
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: