Monday, April 15, 2019

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

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 08 02:42PM +0200

On 08.04.2019 14:14, James Kuyper wrote:
> argument where the connection is logically valid, but one or more
> premises is incorrect, is not fallacious, it's merely wrong, and that's
> the case with this argument.
 
Out of context, say as the start of a new thread, it could have been
merely wrong, as an argument merely about the standard's wording.
 
It was however posted in the context of discussing interpretations of
that wording. With the implication that it was relevant to that
discussion. As such it was a fallacy. /And/ wrong.
 
Cheers & hth.,
 
- Alf
Bonita Montero <Bonita.Montero@gmail.com>: Apr 08 05:06PM +0200


> It seems that if you want an way to specify the n'th element of the
> vector, you don't want an iterator, but an numerical index, and use
> indexing operations on the vector.
 
No, i want to use iterators.
 
> an extension of a pointer that when working on a sequence always points
> to a GIVEN item, and the invalidation rules tells you when that
> assumption no longer holds.
 
The invalidation-rules are not necessary here. I gave a nearby implemen-
tation of erase and this implementation doesn't invalidate the iterators
beginning with the erased element. And guaranteeing that the iterators
remain valid doesn't put any restrictions on the implementation.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 03:45AM -0700

> an extension of a pointer that when working on a sequence always points
> to a GIVEN item, and the invalidation rules tells you when that
> assumption no longer holds.
 
There is a key idea here, which I don't remember having seen
before. Thank you for giving this explanation.
Paavo Helde <myfirstname@osa.pri.ee>: Apr 08 08:20PM +0300

On 8.04.2019 18:06, Bonita Montero wrote:
> tation of erase and this implementation doesn't invalidate the iterators
> beginning with the erased element. And guaranteeing that the iterators
> remain valid doesn't put any restrictions on the implementation.
 
So what prohibits you from using your own implementation instead of
std::vector::erase()? It looks like nobody else has any problem with the
current wording of the standard, so a custom solution for your specific
needs seems appropriate.
 
PS. Your implementation lacks a std::move(), without it there would be
some unneeded overhead when copying non-trivial types.
James Kuyper <jameskuyper@alumni.caltech.edu>: Apr 08 08:14AM -0400

On 4/5/19 10:33 PM, Alf P. Steinbach wrote:
>> incorrectly assumed that "gcc folk" didn't exist yet at the relevant
>> time.
 
> Yes, his argument totally lacked any logic.
 
Incorrect - the logic of his argument was perfectly valid. The only
problem was that one of his premises was incorrect. And it wasn't
sufficiently incorrect to completely invalidate the conclusion. If you
replace the premise with "gcc was quite young at the time the decision
was made", then all you have to do is modify the conclusion slightly -
instead of "it's impossible for gcc to have influenced the decision",
say instead that "it's improbable that gcc significantly influenced the
decision".
 
The weakened conclusion is still strong enough to justify presenting it.
 
>> did) read those words at some later time and form an interpretation of
>> them is completely irrelevant to the point he was making.
 
> Right again, it was a fallacious argument, one with no inner logic.
 
In a logical argument, you have premises which are assumed correct, a
conclusion that you're trying to prove, and an argument which is
supposed to connect those premises to that conclusion. A fallacious
argument is one where the logic of that connection is invalid. An
argument where the connection is logically valid, but one or more
premises is incorrect, is not fallacious, it's merely wrong, and that's
the case with this argument.
Bonita Montero <Bonita.Montero@gmail.com>: Apr 08 07:32PM +0200

> PS. Your implementation lacks a std::move(), without it there would be
> some unneeded overhead when copying non-trivial types.
 
I added a follow-up-posting where I added the move.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 08 04:09PM +0200

> The only thing that can make an argument fallacious is a violation of
> the rules of logic - context can never turn a logically valid argument
> into an invalid one.
 
I don't think so, for example because this very response is a
counter-example.
 
 
Cheers!,
 
- Alf
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 03:40AM -0700


>> [...]
 
> Could you please stop replying to my posts. I find your condescension
> and overall weirdness unappealing. TIA.
 
The newsgroup is a public forum. I'm sorry if my comments came
across as condescending; that doesn't match my mindset while
I was writing nor my opinion of you generally.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 10 08:52PM -0700

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
 
[...]
 
> I'm sorry, I'm getting old, and today had my third kidney stone
> trying to take me on. [...]
 
I am truly sorry to hear you are going through this. I will
hold off on responses in this thread for at least a few days
to give that some time to resolve. I hope you feel better
soon.
Tim Rentsch <tr.17687@z991.linuxsc.com>: Apr 09 02:23AM -0700


> There is no way to say that the program itself, without considering
> its invocation, has UB or no UB. It has the potential for UB. For some
> input.
 
My apologies for the long delay in responding.
 
Clearly programs that depend on one or more input values may have
undefined behavior for some particular sets of input values. But
that doesn't mean all programs may exhibit undefined behavior.
Note several points:
 
(A) The program shown depends on an external input;
 
(B) The value of the external input is held in the variable
'n', which is represented in the abstract machine;
 
(C) The circumstance of undefined behavior arises from
evaluating the '/' operator; and
 
(D) The division operation has undefined behavior because
there is an explicit stipulation of undefined behavior
when the denominator has the value zero.
 
Now consider this program:
 
#include <stdio.h>
 
unsigned ss( unsigned, unsigned );
 
int
main(){
printf( " result is %u\n", ss( -1, 0 ) );
return 0;
}
 
unsigned
ss( unsigned n, unsigned r ){
return n ? ss( n-1, r + n*n ) : r;
}
 
There is no external input. Moreover all of the program's
constituent elements are well defined: no 'shall' clauses are
violated, there are no explicit stipulations of undefined
behavior, and there is an explicit definition of behavior for
each program construct. In particular the behavior of the
function call is defined, with no qualifying statement about
memory being available. Do you agree with all that? If not
which part(s) do you not agree with?
 
(My comments here are meant to apply to both C and C++, with the
same conclusions in the two cases. If you think there are any
differences between the two please say what those are and why.)
Paavo Helde <myfirstname@osa.pri.ee>: Apr 09 02:06PM +0300

On 9.04.2019 12:23, Tim Rentsch wrote:
> ss( unsigned n, unsigned r ){
> return n ? ss( n-1, r + n*n ) : r;
> }
 
FWIW, this program appears to compile and run properly in MSVC 2017
Release x64 build, and produces output:
 
result is 2147483648
Sam <sam@email-scan.com>: Apr 10 06:12PM -0400

Alf P. Steinbach writes:
 
> {
> mutex m;
> Lock execution_lock( m );
 
A very cursory attempt to understand this: this is a std::unique_lock, that
locks this thread's mutex. A pointer to this std::unique_lock gets added to
a shared queue. Some other execution thread apparently move-constructs, via
the queued pointer to this std::unique_lock, off the queue, and into an
automatically-scoped variable, which goes out of scope and gets destroyed.
 
I think that's what's going on here. Not 100% certain, but that seems to be
the gist of it. There's some other code that deals with thread
synchronization, but I this looks like the key part:
 
Lock moved_lock = move( *popped( m_execution_locks_q ) );
log( "Thread "s << this_thread::get_id() << " moving the
lock succeeded." );
moved_lock.unlock(); // Another thread runs.
Destructor
would do it anyway.
log( "Thread "s << this_thread::get_id() << " release
succeeded." );
}
 
This seems to be phishing out the pointer from the queue, and std::move-s it
into "moved_lock", in a different execution thread.
 
The very first sentence on
 
https://en.cppreference.com/w/cpp/thread/mutex/unlock
 
specifies the following:
 
# The mutex must be locked by the current thread of execution, otherwise,
# the behavior is undefined.
 
As far as I can tell, the shown code ends up unlocking a mutex in a
different execution thread. As Mr. Spock would say: "highly illogical".
Sam <sam@email-scan.com>: Apr 10 07:40PM -0400

Alf P. Steinbach writes:
 
>> different execution thread. As Mr. Spock would say: "highly illogical".
 
> Thanks. I don't understand why the restriction, but given that it's there,
> what can I do? Is this where condition variables are needed?
 
Yes. A mutex, a condition variable, and a bool flag can be used to implement
a logically-equivalent locking abstraction that can be unlocked by a
different execution thread.
 
The bool flag's initial value is false.
 
Your thread-independent locking operation consists of locking the
std::mutex, and waiting on the condition variable until the bool flag is
false, then setting it to true, then unlocking the mutex.
 
Your unlock operation consists of locking the std::mutex, setting the bool
flag to false, notify_all() the condition variable, then unlocking the mutex.
 
Your code is also quite vulnerable to undefined behavior due to the lifetime
of its std::mutexes which are instantiated in automatic scope. If the
std::mutex goes out of scope and gets destroyed while some other execution
thread still attempts to screw around with it, more undefined behavior.
 
I haven't analyzed whether the shown code guarantees that all references to
the mutex are gone, before it gets destroyed. But it should not be necessary
to rely on this rather fragile dependency. It's far more reliable to use
smart pointers to dynamically-allocated objects with your mutex, condition
variable, and the bool flag, and have a queue of smart pointers. Whichever
thread ends up having the last smart pointer to the object go out of scope
will destroy it, without worrying about making sure that it's the right
thread.
Paavo Helde <myfirstname@osa.pri.ee>: Apr 11 09:50AM +0300

On 11.04.2019 1:28, Alf P. Steinbach wrote:
 
>> As far as I can tell, the shown code ends up unlocking a mutex in a
>> different execution thread. As Mr. Spock would say: "highly illogical".
 
> Thanks. I don't understand why the restriction,
 
A mutex is a very simple concept. You lock the mutex for doing some
modifications on a shared data state which must appear as a single
atomic operation to other threads.
 
If the mutex is locked and unlocked in different threads, then the
operation does not look very atomic to me any more.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 11 12:28AM +0200

On 11.04.2019 00:12, Sam wrote:
> # the behavior is undefined.
 
> As far as I can tell, the shown code ends up unlocking a mutex in a
> different execution thread. As Mr. Spock would say: "highly illogical".
 
Thanks. I don't understand why the restriction, but given that it's
there, what can I do? Is this where condition variables are needed?
 
I'm possibly not quite logical because on painkillers. But.
 
 
Cheers!,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Apr 10 11:08PM +0200

On 10.04.2019 22:40, Chris M. Thomasson wrote:
> of the $... stuff? Something that just uses std primitives, perhaps? I
> have to learn what those $ things mean "under the covers" in order to
> help. Humm...
 
Done. It's just that I prefer coding up things with the macros, cause
it's less to write and less to read. Thanks.
 
 
#if 1
// include <cppx-core/all.hpp> //
https://github.com/alf-p-steinbach/cppx-core
#include <iostream>
#include <stdexcept>
#include <thread>
#include <mutex>
#include <queue>
#include <sstream>
#include <string>

No comments: