Sunday, June 21, 2020

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

Scott Newman <scott69@gmail.com>: Jun 16 05:12PM +0200

Am 15.06.2020 um 09:03 schrieb Chris M. Thomasson:
>     return reinterpret_cast<char*>(this + 1);
>   }
> };
 
Don't care for the spec. It works with any compiler and
it will work with any compiler that will ever exist.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jun 17 12:24AM +0100

On Tue, 16 Jun 2020 16:11:31 -0700
> So, basically, I need to use placement new and explicit dtor via
> calling the dtor ~Type(). Then it becomes a "real object" in C++. I
> thought that POD would be different in a sense.
 
Yes, although you don't actually need to call the destructor because
your types are trivial.
 
But there are other issues with your code which I have alluded to in
other posts. I should use 'new unsigned char[...]' instead of
std::malloc, placement new your 'header' struct into it and (as you do
at present) cast the buffer part to char* if you really want char*
instead of unsigned char* for the buffer. As I have indicated in those
posts I think that cast is valid but you never know with C++17/20: if
the committee don't understand the rules who are we to say.
 
As I have also mentioned in other posts I agree with your sentiments
about PODs/trivial types. That seems to me to be another fail in the
standard. It ought to be valid in my view, but it isn't.
Scott Newman <scott69@gmail.com>: Jun 17 09:06AM +0200

>> Not in this case.
 
> What do you mean? The compiler is *always* allowed to do whatever it wants
> if something is UB.
 
There's no UB with what Chris does initially.
Manfred <noname@add.invalid>: Jun 17 03:27PM +0200

On 6/17/2020 12:39 AM, Chris M. Thomasson wrote:
 
>> Would would one need to cast the return value of malloc to (X*)?
 
> Why would one need to cast the return value? void* can do it as is,
> right? In pure C...
 
In C yes, in C++ a type cast is required. A static_cast would suffice.
 
This is why in my other posts I wonder why such a type cast could not be
enough (at least for PODs) to overcome the issue about object creation
and lifetime that is described in the proposal.
Instead of going down some contrived path like requiring malloc to "look
into the future" and such.
Manfred <noname@add.invalid>: Jun 17 03:35PM +0200

On 6/17/2020 1:11 AM, Chris M. Thomasson wrote:
 
> Touche! So, basically, I need to use placement new and explicit dtor via
>  calling the dtor ~Type(). Then it becomes a "real object" in C++. I
> thought that POD would be different in a sense.
 
If you look at the quote from Bjarne's "The C++ Programming Language"
that I posted earlier you see that he himself does not require using
placement new for malloc on a type with no constructor like this.
Apparently, for some reason, the standard landed somewhere else.
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 15 04:04PM -0700

On 6/15/2020 3:52 PM, Chris M. Thomasson wrote:
>> to over-engineer it if you never intend to use it in a larger program.
 
> raii would not hurt here, imagine that the code is as it is. Well, we
> can wrap it up. Imvho, its a nice convenient feature of C++.
For some reason this reminds me of some of my older memory allocators
where the header was aligned on a large boundary. I could do it two
ways. One was round down to get at the header, and another experiment
rounded down then subtracted the size of the header.
 
Take a cache line allocator, if the header fits in a cache line, then it
can be the first element in an array of lines.
Scott Newman <scott69@gmail.com>: Jun 15 07:42PM +0200

> (assuming a non-empty vector).
> The latter form will abort the program with some existing C++
> implementations, so it's not only a formal difference.
 
That's not what we were discussing. It's just this:
> return reinterpret_cast<char*>(this) + sizeof(*this);
vs.
> return reinterpret_cast<char*>(this + 1);
 
Even if you use C-style casts in the latter case there won't be ever
any implementation which would misbehave here. Your code-experiments
are esoterics.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jun 21 01:09AM -0400

On 6/20/20 11:50 AM, Manfred wrote:
 
> I am no expert on this point, rather I am curious: does the standard say
> something explicit (if so, a pointer would be appreciated) about
> converting iterations into a recursive function, ...
 
No.
 
> ... or is this "permission"
> merely based on the lack of prohibition under the umbrella of the "as
> if" rule?
 
In the context of C or C++, "observable behavior" is a special piece of
jargon defined by the relevant standard - that definition is not
"behavior which is observable". When that phrase is used by someone who
understands that definition, it is always in reference to the as-if
rule, because the relevant standard uses that term only in the context
of that rule.
 
> time) than iterative ones, so the source code may have well defined
> behavior in the iterative form, but run into UB in the recursive form
> due to resource exhaustion.
 
A program that exceeds an implementation's limit may not be successfully
processed (See 4.1p2 and Annex B). However, the standard sets no minimum
value on any of those limits (the values shown in Annex B are merely
recommendations and guidelines). It also fails to impose any limits on
how much memory any particular piece of code may require. Therefore, any
program might exceed those limits, whether a loop is handled iteratively
or recursively.
It's entirely a matter of QoI whether an implementation decides to
implement any code in any manner that doesn't exceed it's own limits.
During one memorable discussion, the person I was talking with was
actually complained about the supposed "misinterpretation" of the
standard as allowing an optimization that greatly reduced the likelihood
of resource exhaustion (though he never acknowledged the truth of the
claim that it would have had that effect - he just ignored that
assertion completely).
 
>> observable behavior (in this case, none). It would be hard to convince
>> anybody to use such a compiler - but that's what QoI is about.
 
> Alf mentioned resource usage, not just time.
 
My comment was about all such resources, I just used time as an example.
 
> ... In this case running out of
> stack space is a typical risk to be managed, which does not apply to
> iterative loops.
 
Any program, even "int main(void) {}", may be implemented in such a
fashion as to exceed an implementation's resource limits. It's only a
matter of QoI whether or not that actually happens.
Juha Nieminen <nospam@thanks.invalid>: Jun 21 01:54PM

> you won't find malloc() or free() in kernel code you wouldn't find any of the
> STL or shared pointers or virtual functions or frankly anything that makes C++
> useful.
 
Actually many of the utilities provided by the C++ standard library can
be very useful even if you are required to avoid dynamic memory allocation.
 
For example, std::unique_ptr is *not* restricted to simply manage
dynamically allocated memory for you. It can perfectly well (and
relatively easily) be used to manage other resources as well. For
example, you can use a `std::unique_ptr` to automatically close
a FILE* that you have std::fopen()'ed, when the pointer goes out
of scope. No dynamic memory allocation involved here (unless
std::fopen() itself does).
 
Also, in fact, all the dynamic data containers provided by the
standard library can be used without them calling the default
'new'. You can provide them with your own allocator, if you so
wish. This allocator could manage memory in a static array,
for example. There may be situations where this could be useful.
 
There's also, of course, a huge amount of utilities in the standard
library that are not related to dynamic memory allocation, such
as the utilities in <algorithm> and many of the other headers.
 
It is perfectly possible to get a lot of benefit from C++ without
having to go to dynamic memory allocation and virtual functions.
"Öö Tiib" <ootiib@hot.ee>: Jun 21 09:59AM -0700

On Sunday, 21 June 2020 16:54:43 UTC+3, Juha Nieminen wrote:
> a FILE* that you have std::fopen()'ed, when the pointer goes out
> of scope. No dynamic memory allocation involved here (unless
> std::fopen() itself does).
 
That is generally good example but it coincides with one thing that
most programs handle lousily. If file was fopened for writing then
the very rare cases when fclose can fail are likely quite important
to handle properly. Unhandled failure may mean that users did lose
their data. That problem does not magically disappear when
fclose is abstracted away into deleter of unique_ptr.
Jorgen Grahn <grahn+nntp@snipabacken.se>: Jun 21 06:02PM

On Sun, 2020-06-21, Öö Tiib wrote:
> On Sunday, 21 June 2020 16:54:43 UTC+3, Juha Nieminen wrote:
...
> to handle properly. Unhandled failure may mean that users did lose
> their data. That problem does not magically disappear when
> fclose is abstracted away into deleter of unique_ptr.
 
And it doesn't disappear if you use a std::fstream.
 
(Not that I always handle the error myself.)
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
mehrdad <m-ghassempoory@ntlworld.com>: Jun 21 06:05PM +0100

I used to be a programmer. I had a good working knowledge of C++, but I
have not been programming for the last 10-12 years. In my retirement I
decided to catch up with the changes in the language. I need a good
reference book on C++ which covers everything (preferably) up to C++ 17.
I do have the C++17 book by N.M. Josuttis, but it seems to be like an
update document rather than a reference book. What I DO NOT need is a
book that tries to teach programming using C++. Any ideas?
"Öö Tiib" <ootiib@hot.ee>: Jun 21 10:38AM -0700

On Sunday, 21 June 2020 20:06:00 UTC+3, mehrdad wrote:
> I do have the C++17 book by N.M. Josuttis, but it seems to be like an
> update document rather than a reference book. What I DO NOT need is a
> book that tries to teach programming using C++. Any ideas?
 
To get update what C++11/C++14 added perhaps buy that pdf from Scott
Meyers <https://www.artima.com/shop/overview_of_the_new_cpp>
Update to C++17 you already have you said.
About reference I think <https://en.cppreference.com/w/> is really
good reference (when there is internet access).
Most of the good books try to teach deeper tricks how to use one or
other feature of C++ conveniently, but that you said you do not need
in full caps.
woodbrian77@gmail.com: Jun 20 04:56PM -0700

On Thursday, June 18, 2020 at 9:02:31 PM UTC-5, Lynn McGuire wrote:
> published."
 
> "The C++ community is really excited about C++20. It looks like a
> groundbreaking update similar to C++11.
 
I like span, but have yet to determine how coroutines
would be helpful to me. I'm going to stick with 2017
C++ for my open source code for now.
 
 
Brian
Ebenezer Enterprises - Enjoying programming again.
https://webEbenezer.net
Juha Nieminen <nospam@thanks.invalid>: Jun 21 02:08PM

> I like span, but have yet to determine how coroutines
> would be helpful to me. I'm going to stick with 2017
> C++ for my open source code for now.
 
Coroutines are a very hard beast to understand, even for a very
experienced programmers. Both how they work, how they are used,
and what they are useful for, can be really obscure (and sometimes
hard to explain).
 
Here's one practical real-life example of where coroutines can be
useful:
 
Suppose you have a compressed file format decompressor. Quite often
you don't want to decompress the entire input file at once into RAM,
because the decompressed data can be enormous in size (too large to
even fit in RAM at once), and thus you want to decompress and process
it in chunks.
 
For example, you might want to decompress and hande 1 MB of (decompressed)
data at a time. You might even want, for efficiency, to have a 1 MB
static C-style array into which you decompress the data to to be
handled. In other words, decompress data from the input file into
the 1 MB array, and when the array gets full, handle that data,
and then continue decompressing more data into the same array,
starting from the beginning.
 
But this poses a problem: Most likely when you are decompressing
the data from the input file, it won't come in nice 1 MB chunks.
At some point something in the compressed input will probably
produce a chunk of data that would overflow the array. It won't
fit in the remaining space in the array.
 
In other words, you would need to stop decompressing the current
compressed block at the exact moment when the 1 MB array gets full,
call the routine that consumes the array, and then continue from
where you left off, writing the rest of the decompressed block to
the beginning of the array.
 
In order to be able to do this, you need to store the state of the
decompressor in full. It needs to be able to stop, jump somewhere
else, and then continue exactly from where it stopped.
 
This is certainly possible with current C++, but it can become
complicated. You need to not only store all the state of the
decompressor inside something (usually a class or struct), but to
also design your decompressor code so that it can continue exactly
from where it stopped (which, depending on the complexity of the
compressed file format, can become quite complicated).
 
This is where coroutines step in to help, as they automatize the
vast majority of that: At any point in your decompressor code you
can "yield", which jumps back to whatever called the decompressor,
and when that's done, it can return to the exact point where you
yielded, and the decompressor can continue as if nothing had happened.
The entire state at that point in the code is restored automatically.
 
This simplifies *significantly* this kind of situation, requiring the
programmer to do significantly less work to achieve this. The state is
stored automatically, and the routine can easily continue from wherever
there's a "yield", no matter where it is in the code, or how many
yield points there may be. Even if there's a dozen points in the
decompressor where the target buffer may get full, it doesn't matter.
The next time the execution returns to it, it will continue from that
point.
Bart <bc@freeuk.com>: Jun 13 12:01PM +0100

> variable length nature of the flexible structure. The compiler
> would inject code to compute properly based on the runtime obser-
> vation of the dynamics of the particular instance.
 
This for a new language? There are a few other approaches that might be
better.
 
But first, what exactly is the structure above - is the char data held
directly inside the struct? That's going to be awkward where you have
two of them.
 
How does it work exactly: do first/lastNameLength need to be determined
at the same time, and struct size calculated for both (sizeof(int)*2 +
firstlength+lastlength, +2 if zero-terminated), and then there are
fixed? How do the lengths get into the struct? What happens when you
pass a var_char to a function, does it somehow include its length, or do
you need the length passed explicitly?
 
Also, how does an access such as X.lastNameLength or X.lastname know the
offsets of those members, if they will depend on the X.firstNameLength?
 
If you say the compiler will sort it out, then I can gave a dozen
examples where it will have its work cut out to determine not only how
to do something, but what it even means.
 
I mentioned other ways, but since this is C++, why not just use its
'string' type? It includes its length, the two strings can be created at
different times, and there's no extra housekeeping for the lengths. But
the string data will be on the heap.
 
If it's necessary for the string data to be part of the struct, how
important is it that the struct is the exact size of the combined
strings? Having a fixed capacity is much easier, if these names will be
of a limited length.
 
There are also schemes where you allocate a fixed size in-place string,
but provide a mechanism for longer strings too, which are stored
elsewhere via a pointer. (Something like this is done in COFF files'
symbol tables.)
 
> Chris Thomasson, I wanted to get your input.
 
I forgot this bit. Please ignore the above...
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 14 05:53PM -0700

> {
> augment SList* data; // Changes void* to SList*
> };
[...]
 
At first glance maybe something like:
________________________
#include <iostream>
 
 
struct SWhatever
{
void* data;
};
 
 
struct SFoo
{
SFoo(int data_) : data(data_)
{
std::cout << this << "::SFoo::SFoo(" << data << ")\n";
}
 
~SFoo()
{
std::cout << this << "::SFoo::~SFoo(" << data << ")\n";
}
 
int data;
 
void bar()
{
std::cout << this << "::SFoo::bar(" << data << ")\n";
}
};
 
 
struct SWhateverShim
{
SWhatever whatever;
 
SWhateverShim(SWhatever const& whatever_) : whatever(whatever_) {}
 
SFoo* get() const
{
return static_cast<SFoo*>(whatever.data);
}
 
SFoo* operator ->() const
{
return get();
}
};
 
 
int main()
{
{
SWhatever wever;
 
wever.data = reinterpret_cast<void*>(new SFoo(123));
 
SWhateverShim shim(wever);
 
shim->bar();
 
delete shim.get();
}
 
return 0;
}
________________________
 
 
Is that helpful at all Rick?
Cholo Lennon <chololennon@hotmail.com>: Jun 16 04:16PM -0300

> Wuhan virus and checking temperatures. I'm happy
> to report that I don't have any symptoms at this
> time and hope to keep it that way.
 
"Wuham virus"? :-O the virus has a name. Maybe, using your bias, we
should use "the state where police kill non-white people" instead of
Minnesota, or even better... Killersota... (yes, I have plenty of
biased/stupid "names")
 
 
--
Cholo Lennon
Bs.As.
ARG
David Brown <david.brown@hesbynett.no>: Jun 16 09:14AM +0200

On 15/06/2020 23:44, Frederick Gotham wrote:
> }
> }
> }
 
How about :
 
if (cond1 && cond2 && cond3 && cond4) {
DoSomething();
}
 
 
 
> if ( !cond3 ) return;
 
> if ( !cond4 ) return;
 
> Do Something();
 
That's good for some kind of tests. In particular, tests on the
parameters of a function followed by early exits are a popular style.
(Not everyone likes it - some people feel functions should only ever
have one exit.)
 
There is no single "best" method - it will depend on the code as well as
any style preferences or requirements for the project and team.
 
 
> Do Something();
 
> Label_At_End:
> ;
 
That's also a common idiom. It's not one I like - I don't find use for
gotos in my own code. But some people do.
 
 
 
> if ( !cond4 ) break;
 
> Do Something();
> }
 
That would be a code review fail right away - it's an unnecessarily ugly
hack and an abuse of switch. Your "do {} while (false);" is much less
bad (omitting the "default:").
 
 
> Do Something();
> } while (false);
 
> Does anyone else use fake switches and fake loops like this just to exploit the 'break' keyword?
 
I've never felt the need.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 02:26AM +0100

> always praying for them, always helping them, showing them the love
> and patience of God alive inside you.
 
> You cast things upon me which are not me or mine.
 
You are a bigot; and based on what you have just said: a two faced bigot, the worst kind.
 
/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."
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 13 01:49AM +0100

> same: A hardware and software stack written from scratch, given over
> to God explicitly, through prayer and sanctification.
 
> CPU, OS kernel, drivers, apps. A usable system for daily use.
 
Yeah, Terry would be proud. Two peas in a pod, growing in a field off Bigot Lane.
 
/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>: Jun 16 09:02PM +0200

>> (and the other data types) into a single method ?
 
> Try std::variant<...>.
> But that's less performant.
 
How about this:
 
#include <variant>
#include <vector>
#include <string>
 
using namespace std;
 
struct DataItem
{
int aAvalueInt;
double aValueDouble;
vector<int> aValueIntArray;
vector<string> aValueStringArray;
};
 
using var_t = variant<int, double, vector<int>, vector<string>>;
 
void f( var_t &var, DataItem &di )
{
enum
{
INT,
DOUBLE,
VEC_INT,
VEC_STR
};
switch( var.index() )
{
case INT:
di.aAvalueInt = get<INT>( var );
break;
case DOUBLE:
di.aValueDouble = get<DOUBLE>( var );
break;
case VEC_INT:
di.aValueIntArray = get<VEC_INT>( var );
break;
case VEC_STR:
di.aValueStringArray = get<VEC_STR>( var );
break;
}
}
 
Compile it with C++17 enabled.
Lynn McGuire <lynnmcguire5@gmail.com>: Jun 16 01:39PM -0500

Hi,
 
Is there a way to have the same method but with a different argument
data type for a single argument ? For instance, the following methods
that I have greatly simplified:
 
class DataItem : public ObjPtr
{
int aAvalueInt;
double aValueDouble;
std::vector <int> aValueIntArray;
std::vector <std::string> aValueStringArray;
}
 
ObjPtr * DataItem::store(int aValue)
{
// do some stuff
aValueInt = aValue;
// do some stuff
return this;
}
 
ObjPtr * DataItem::store (double aValue)
{
// do some stuff
aValueDouble = aValue;
// do some stuff
return this;
}
 
ObjPtr * DataItem::store (std::vector <int> aValue)
{
// do some stuff
aValueIntArray = aValue;
// do some stuff
return this;
}
 
ObjPtr * DataItem::store (std::vector <std::string> aValue)
{
// do some stuff
aValueStringArray = aValue;
// do some stuff
return this;
}
 
Is there some way to combine all of these methods (and the other data
types) into a single method ?
 
Thanks !
 
Lynn
"Chris M. Thomasson" <chris.m.thomasson.1@gmail.com>: Jun 14 05:34PM -0700

On 6/14/2020 4:58 PM, Mr Flibble wrote:
> Apparently you shouldn't prick your sausages. I've been doing it wrong
> all these years.
 
If you prick them, then all of the juices will most likely leak out
during the cooking process: they will probably dry out.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jun 13 11:16PM -0700

> Keith Thompson wrote:
[...]
> more like 1988 if you believe to Wikipedia. I recall first learning about it
> circa 1993. Back then, any reference to UNIX would elicit a quip "which UNIX?"
> from one shrewd friend of mine.
 
In fact Wikipedia is where I got that information. I blame the
standard that puts the '8' and '9' keys next to each other on
my keyboard. (Yes, I meant to type 1988.)
 
--
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 */
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: