Thursday, December 17, 2020

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

olcott <NoOne@NoWhere.com>: Dec 16 09:58PM -0600

On 12/16/2020 7:48 AM, Malcolm McLean wrote:
> all, you need some framework for running Turing machines, and for stopping
> them when they get caught in infinite loops (or exceed the patience of
> the user).
 
The global Halts merely examines the execution trace of each and every
user specified x86 instruction that is executed by the x86utm operating
system.
 
Since the global Halts() is an intrinsic part of this operating system
its behavior is a function of the sequence of all of the simulated user
specified instructions. This would seem to make it a pure function of
its inputs.
 
Local Halts() is the same situation except that its scope is the
sequence of simulated user specified x86 instructions that it began the
invocation of.
 
> You haven't met Ben's challenge because of this
 
When Ben expects the infinite invocation of any function to return a
value to its caller Ben is nuts.
 
--
Copyright 2020 Pete Olcott
 
"Great spirits have always encountered violent opposition from mediocre
minds." Einstein
olcott <NoOne@NoWhere.com>: Dec 17 09:07AM -0600

On 12/17/2020 8:34 AM, Ben Bacarisse wrote:
> the "outer" assessment must get an infinite number of cases wrong. We
> won't get to see that, though. In fact, I doubt it even exists except
> for a couple of special cases.
 
All that I have to do to refute the {Linz, Sipser, and Kozen} proofs is
to show how Halts decides their {Ĥ, D, and N} counter examples as a
function of their sequence of instructions that Halts simulates. A
simulator has access to the sequence of instructions that it simulates.
 
A partial halt decider that correctly decides the counter-example basis
of the conventional halting problem proofs is sufficient to refute these
proofs.
 
--
Copyright 2020 Pete Olcott
 
"Great spirits have always encountered violent opposition from mediocre
minds." Einstein
Bonita Montero <Bonita.Montero@gmail.com>: Dec 17 03:35PM +0100

The class packaged_task<> doesn't has a copy-constructor, but it can be
moved. But I need a copyable packaged_task which needs only to work with
the object returned by bind(). The bind()-objects are copyable so this
should be possible. How do I write such kind of packaged_task<> on my
own ?
Bonita Montero <Bonita.Montero@gmail.com>: Dec 17 03:54PM +0100

> the object returned by bind(). The bind()-objects are copyable so this
> should be possible. How do I write such kind of packaged_task<> on my
> own ?
 
I've just were noticed that there's std::function<>, which does what
I need. But it would be nice to know how such a class is built.
David Brown <david.brown@hesbynett.no>: Dec 17 03:01PM +0100

On 17/12/2020 05:01, Brian Wood wrote:
>> without getting side-tracked, and perhaps you'll get a little of the
>> help you want.
 
> I'll post as I see fit. Without fear of jackasses.
 
Of course you will post as you see fit - this is an unmoderated group.
Others can give you advice, or ask you nicely, or ask you less nicely,
but in the end it is only you that decides how you post - and whether
you do so in a way that will get you useful answers, or merely annoy people.
 
 
> These are some functions in my repo. I'd like to know
> if they could be rewritten as lambdas. I've tried a bit,
> but haven't found a way to do it. Tia.
 
Below is my attempt.
 
Getting recursive lambdas to work can be an interesting challenge. But
I don't know why you'd want to do so here - the template functions are
fine, and IMHO clearer than lambdas.
 
 
 
 
#include <iostream>
 
class Failure {
public:
Failure(const char * s) {
std::cout << s << ": ";
}
Failure& operator << (int x) {
std::cout << "<" << x << ">";
return *this;
}
Failure& operator << (const char* s) {
std::cout << s;
return *this;
}
};
 
template<class E>void apps (E&){}
template<class E,class T,class...Ts>void apps (E& e,T t,Ts...ts){
e<<t; apps(e,ts...);
}
 
template<class E=Failure,class...T>[[noreturn]]void raise (char const
*s,T...t){
E e{s}; apps(e,t...); throw e;
}
 
auto lambda_apps = [](auto e, auto ...ts) {
auto imp = [](auto& apps_ref, auto e, auto ...ts) {
if constexpr (sizeof...(ts)) {
[](auto& apps_ref, auto e, auto t, auto ...ts) {
(e << t);
apps_ref(apps_ref, e, ts...);
}(apps_ref, e, ts...);
}
};
return imp(imp, e, ts...);
};
 
template<class E = Failure>
auto lambda_raise = [](const char* s, auto ...ts) {
E e{s};
lambda_apps(e, ts...);
throw e;
};
 
int main(void) {
std::cout << "Using template functions\n";
 
Failure f1("Hello");
apps(f1, 1, 2, 3);
try {
raise("Bad", 5, 6, 7);
} catch (Failure) {
std::cout << " Failure ";
} catch (...) {
std::cout << " Something else ";
}
 
std::cout << '\n';
std::cout << "Using lambdas\n";
 
Failure f2("Hello");
lambda_apps(f2, 1, 2, 3);
try {
lambda_raise<>("Bad", 5, 6, 7);
} catch (Failure) {
std::cout << " Failure ";
} catch (...) {
std::cout << " Something else ";
}
 
std::cout << '\n';
 
}
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Dec 13 09:14PM +0100

On 13.12.2020 14:35, Marcel Mueller wrote:
> functions that need to be called manually for every class instance. So
> it is correct but useless. From my point of view a language must be
> first of all useful.
 
One of the most common kinds of bug in Java/C# is calling a derived
class method or during initialization, before the derived class' class
invariant (the basic assumptions about the state) has been established.
 
That bug is almost non-existent in C++, due to the behavior described
above. That absence of a whole kind of problem is IMO very useful.
 
- Alf
Bonita Montero <Bonita.Montero@gmail.com>: Dec 13 09:19PM +0100

> While formally correct I never found a practical use case for this
> behavior.
 
Doesn't matter. As you can see from my experience the whole magic
is optimized away by the compiler (needing optimizations spanning
the translation-units, i.e. link-time code-generation) when it
thinks there won't be any virtual calls in the destructor-chain.
Someone may consider this a bug because there might be virtual
method calls from different threads.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 13 10:39AM +0100

I had a nice bug: I've got a base-class with a pure virtual function
which is overridden in a derived class. This function is virtually
called by a thread from a thread pool (through a static proxy-func-
tion). In the destructor of the base-class I wait for all threads
from the thread pool to have finished their work and that there are
no more items in their work-queue.
What I missed was, that as soon as the base-class destructor is called
the virtual fuction pointer is adjusted to the pointer of the base-class
(I'm wondering that is there any because a base-class with a pure vir-
tual function shouldn't have a virtual method table at all). So before
I could wait for the threads to finish all work the null pure virtual
function got called. ;-)
Interestingly this doesn't happen if I don't compile the code as debug
-code. So the compiler indirectly gives me a hint here for a possible
bug.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 14 07:10AM +0100

> Try to emulate in Relacy.
 
Not necessary, it's already tested.
Paavo Helde <myfirstname@osa.pri.ee>: Dec 13 04:00PM +0200

13.12.2020 11:39 Bonita Montero kirjutas:
> tual function shouldn't have a virtual method table at all). So before
> I could wait for the threads to finish all work the null pure virtual
> function got called. ;-)
 
That's what std::shared_ptr is for. By its design you cannot have such
problems (either during construction or destruction) if you access your
shared object via std::shared_ptr pointers only. Whenever you have a
shared_ptr to an object, you can be sure that it points to the most
derived class object (because a shared_ptr cannot be constructed before
the most derived class object is ready, and the destructor of the most
derived class is not evoked while there is a shared_ptr alive).
 
Just stop trying to be too clever for no good, always access your shared
objects via shared_ptr, and adjust the rest of the code to cope with
that simple rule. That's it, a major source of nasty heisenbugs is gone!
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Dec 14 01:07AM

On Sun, 13 Dec 2020 13:50:18 -0800
> object is fully initialized. It is a common error wrt creating thread
> base classes. Try not launch threads in the ctor, that act on the object
> being constructed in the first place!
 
There is no real difference in the requirements for proper sequencing
and (where appropriate) thread synchronization of data objects as
regards code in the body of a constructor and code in the body of any
other method of a class. By the time the constructor is entered all
member sub-objects will have been initialized to their initial state,
so far as they have one (default initialized trivial types may not have
one), including by any member initializer list.
 
The problem is with calling virtual functions in a base constructor.
This is only really acceptable if you suppress the virtual call by
using an explicit base class scope operator.
Bonita Montero <Bonita.Montero@gmail.com>: Dec 13 06:55PM +0100

Here's the current state of my thread-pool-class:
 
// debug_exceptions.h
 
#pragma once
#if !defined try_debug
#if !defined(NDEBUG)
#define try_debug try
#else
#define try_debug

No comments: