Monday, May 13, 2019

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

Thiago Adams <thiago.adams@gmail.com>: May 13 05:39AM -0700

Proposal to add MACRO_ON / MACRO_OFF
What is does?
Is turn ON OFF macro expansion.
 
Motivation
Library implementers, especially inline functions, uses identifiers names
__LikeThis and one reason is to protect the code against some macro created
by the user.
 
In windows we have a classic conflict with min/max from windows.h and min max
from STL.
 
With this feature can protect the code against external interference.
 
How to use?
#define M 1
#pragma STDC MACRO_OFF
 
// the preprocessor will not expand any macro here...
int M = 2;
 
#pragma STDC MACRO_ON
 
Other preprocessor features are not affected and the expansion at for instance #if HERE still allowed.
David Brown <david.brown@hesbynett.no>: May 13 03:37PM +0200

On 13/05/2019 14:39, Thiago Adams wrote:
> int M = 2;
 
> #pragma STDC MACRO_ON
 
> Other preprocessor features are not affected and the expansion at for instance #if HERE still allowed.
 
I suspect that you'd quickly have trouble here - there are /lots/ of
macros defined in most compilations, and many of them are essential. A
quick test of a blank C/C++ file on my system gives 347 pre-defined
macros in C and 389 for C++. If I add "#include <stdint.h>", these
numbers go up to 579 and 671.
 
Some of these macros are going to be directly useful - header files can
quite reasonably include standard library headers like <stdbool.h>,
<stdint.h>, <stddef.h>, and many of the features are defined there as
macros. There are also many macros predefined by tools, or declared by
common OS/library include files, that are useful for more complex
libraries - letting the headers adjust themselves for different
compilers, different target OS's, etc.
 
For C++, the solution to this kind of problem is modules. We don't have
them yet, but I believe they should be here Real Soon Now™. This is in
addition to using other C++ features to avoid macros (like inline
functions, better "const", etc., and namespaces). I think it could be
counter-productive to have a second solution before them.
 
Other than that, I think perhaps you could just track #define's in
"application" code (the main C or C++ file, and any "" includes), and if
any of these are encountered while processing a system include (a <>
include), issue a warning. Aim to encourage users to structure their
code sensibly with their system includes at the start, before local
macro definitions, and to help users spot problems. Then library
writers can use nicer names.
Thiago Adams <thiago.adams@gmail.com>: May 13 07:16AM -0700

On Monday, May 13, 2019 at 10:37:59 AM UTC-3, David Brown wrote:
> quick test of a blank C/C++ file on my system gives 347 pre-defined
> macros in C and 389 for C++. If I add "#include <stdint.h>", these
> numbers go up to 579 and 671.
 
It can be used in small blocks.
 
 
https://stackoverflow.com/questions/11544073/how-do-i-deal-with-the-max-macro-in-windows-h-colliding-with-max-in-std
 
One use case is this one:
 
 
#include <Windows.h> // includes WinDef.h which defines min() max()
#include <iostream>
using std::cin;
using std::cout;
 
#pragma STDC MACRO PUSH OFF
 
void Foo()
{
int delay = 0;
do
{
if(cin.fail())
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
cout << "Enter number of seconds between submissions: ";
} while(!(cin >> delay) || delay == 0);
}
 
#pragma STDC MACRO POP
 
 
In this sample max will not be expanded.
 
(I added PUSH and POP to restore the previous state)
"Öö Tiib" <ootiib@hot.ee>: May 13 07:28AM -0700

On Monday, 13 May 2019 17:16:32 UTC+3, Thiago Adams wrote:
 
> #pragma STDC MACRO POP
 
> In this sample max will not be expanded.
 
> (I added PUSH and POP to restore the previous state)
 
When there is a big enough piece of code without any macro
expansions now then there will be also necessity to add those
into it tomorrow. No matter if it is for debugging, testing, logging,
fixing some portability or compatibility issue ... it will happen.
Result will be code sliced with lot of #pragmas and the purpose
will be anyway broken on some line where both desirable and
undesirable macro expansion happen at same time.
 
Just define NOMINMAX if you ever use windows.h for anything.
Thiago Adams <thiago.adams@gmail.com>: May 13 07:52AM -0700

On Monday, May 13, 2019 at 11:28:40 AM UTC-3, Öö Tiib wrote:
...
> will be anyway broken on some line where both desirable and
> undesirable macro expansion happen at same time.
 
> Just define NOMINMAX if you ever use windows.h for anything.
 
If you think your code will be sliced then dont use this feature.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: May 13 03:39AM +0200

On 13.05.2019 00:52, Manfred wrote:
> positions; since this is an insert() operation there is no overlap.
>   - free the old storage and rebase the vector on the new storage.
> end
 
Not sure exactly what you mean, but the "target position" of the
sequence to be inserted is an iterator into the original storage.
 
To get that position in the new storage one needs an index.
 
That said the logic you sketch, checking if reallocation is needed, is
more elegant than what evolved out of my coding. :-)
 
 
 
>> And that's half of what goes on in the code I posted.
 
>> The rest of that code was about conforming to the (C++17 table 87)
>> prohibition on passing iterators to the vector itself, to `insert`.
 
 
Cheers!,
 
- Alf
Paavo Helde <myfirstname@osa.pri.ee>: May 13 09:15AM +0300

On 13.05.2019 4:39, Alf P. Steinbach wrote:
 
> Not sure exactly what you mean, but the "target position" of the
> sequence to be inserted is an iterator into the original storage.
 
> To get that position in the new storage one needs an index.
 
That's the same as with the regular insert() whenever there is a
reallocation. That's not an issue to be debated.
Juha Nieminen <nospam@thanks.invalid>: May 13 09:49AM

> Experts, why this is implemented as NOT WORKING?
> It's for me as can't understand.
 
Because you are using iterators that are being invalidated while new
elements are being added to the vector.
 
If you do a reserve() call with the final size before the insertion,
it should work.
 
Note, however, that constantly calling reserve() with the new expected
size can actually make std::vector very inefficient.
 
How so? Because most common std::vector implementations will allocate
*exactly* the specified amount of space, if the value you give is
larger than the current capacity.
 
This means that if you do eg. v.reserve(v.size()+1) before each
v.push_back(), those insertions will become linear-time rather
than constant-time. Thus this should be used carefully.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: May 12 05:25PM +0200

On 12.05.2019 17:04, Bonita Montero wrote:
>> before copying it back into the same vector.
 
> The problem is that the vector can't be grown in-place of the capacity
> isn't high enough. So the iterators must be invalid.
 
You can look at the code I posted late-night (for me) in this thread for
a direct counter-example to your assertion regarded as an in-context
argument. The iterators are invalid after the operation, not at the
beginning of it. Keeping things correct during the operation is not
entirely trivial, but it's not difficult either, just typical coding.
 
That code isn't as efficient as if the vector itself had done it,
because the vector has access to uninitialized parts of its own buffer
and that code instead needs to use a separate vector for temp storage,
but it demonstrates that modulo performance there's no problem.
 
The performance is why ideally the vector itself should do it.
 
 
Cheers & hth.,
 
- Alf
Bonita Montero <Bonita.Montero@gmail.com>: May 12 05:44PM +0200

> argument. The iterators are invalid after the operation, not at the
> beginning of it. Keeping things correct during the operation is not
> entirely trivial, but it's not difficult either, just typical coding.
 
This implementation doesn't fit with the C++-paradigm o a minimal
overhead.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: May 12 05:46PM +0200

On 12.05.2019 17:44, Bonita Montero wrote:
>> typical coding.
 
> This implementation doesn't fit with the C++-paradigm o a minimal
> overhead.
 
Prove it, and why that would still hold if the vector did it itself.
 
As far as I'm concerned it's just a nonsense assertion, but there could
always be something I didn't think of.
 
 
Cheers!,
 
- Alf
Bonita Montero <Bonita.Montero@gmail.com>: May 12 06:01PM +0200

>> This implementation doesn't fit with the C++-paradigm o a minimal
>> overhead.
 
> Prove it, ...
 
Have a look at my fix of the OP's code.
There's only _one_ additional reserve().
Bonita Montero <Bonita.Montero@gmail.com>: May 12 08:03PM +0200

> because the standard (in table 87 in §25.2.3/4, a.k.a.
> §sequence.reqmts/4.) requires that iterators passed to `insert` do not
> refer to that container, and that's why I didn't do things that way.
 
Pure theory ...
Bonita Montero <Bonita.Montero@gmail.com>: May 12 08:27PM +0200

> "Neither i nor j are iterators into a", where `i` and `j` are the two
> iterators denoting the range to be inserted by `insert`.
> Cheers & hth.,
 
Pure theory!
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: May 12 08:09PM +0200

On 12.05.2019 20:03, Bonita Montero wrote:
>> §sequence.reqmts/4.) requires that iterators passed to `insert` do not
>> refer to that container, and that's why I didn't do things that way.
 
> Pure theory ...
 
Oh look, here's a link to the corresponding place in the current draft,
 
<url:
http://eel.is/c++draft/sequence.reqmts#tab:containers.sequence.requirements>.
 
Quote:
"Neither i nor j are iterators into a", where `i` and `j` are the two
iterators denoting the range to be inserted by `insert`.
 
 
Cheers & hth.,
 
- Alf
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: May 12 08:01PM +0200

On 12.05.2019 18:01, Bonita Montero wrote:
 
>> Prove it, ...
 
> Have a look at my fix of the OP's code.
> There's only _one_ additional reserve().
 
That has nothing to do with your assertion or proof of it.
 
As it happens your in-practice fix of the OP's code is formally invalid,
because the standard (in table 87 in §25.2.3/4, a.k.a.
§sequence.reqmts/4.) requires that iterators passed to `insert` do not
refer to that container, and that's why I didn't do things that way.
 
If it had been formally valid, say due to the standard having a special
case for random access iterators, then it would not be a /general/ fix
for that case because it requires reserve first, then obtaining
iterators. A fix of that secondary problem, so that one can start out
with the iterators for the range to be inserted, is to check whether the
iterators refer to the vector, and if so transform the iterators into
indices, reserve, then obtain iterators corresponding to the indices.
 
And that's half of what goes on in the code I posted.
 
The rest of that code was about conforming to the (C++17 table 87)
prohibition on passing iterators to the vector itself, to `insert`.
 
 
Cheers & hth.
 
- Alf
Manfred <noname@invalid.add>: May 13 12:52AM +0200

On 5/12/19 8:01 PM, Alf P. Steinbach wrote:
> because the standard (in table 87 in §25.2.3/4, a.k.a.
> §sequence.reqmts/4.) requires that iterators passed to `insert` do not
> refer to that container,
 
Indeed.
 
and that's why I didn't do things that way.
> with the iterators for the range to be inserted, is to check whether the
> iterators refer to the vector, and if so transform the iterators into
> indices, reserve, then obtain iterators corresponding to the indices.
 
I didn't look into your code (too late here for me now), but if the
intention is to solve the prohibition of §sequence.reqmts/4 by
reimplementing a suitable vector, then there should be no need to
convert from iterator to indices and then iterators.
The steroided vector could do the following:
 
if a reallocation is needed, then:
- allocate new storage.
- copy the elements to be inserted from old storage to new storage in
their target positions.
- move all elements from old storage to new storage into their target
positions; since this is an insert() operation there is no overlap.
- free the old storage and rebase the vector on the new storage.
end
 
Iterators pointing into the original vector were valid when entering
insert(), and are invalid upon exit from insert()
 
I guess this is what happens with insert(pos, const T&), i.e. insert a
single element, even if it is a reference into the current vector.
 
Manfred <noname@add.invalid>: May 13 01:59PM +0200

On 5/13/2019 8:15 AM, Paavo Helde wrote:
 
>> To get that position in the new storage one needs an index.
 
> That's the same as with the regular insert() whenever there is a
> reallocation.
Not really, a regular insert can proceed entirely with iterators only,
the problem for a self-referencing insert is that this results in
copying some elements that have already been move()d from.
 
That's not an issue to be debated.
Probably so, if performance is at all affected, it's a matter of
nanoseconds. Effect on code is only a matter of style.
Ike Naar <ike@sdf.lonestar.org>: May 13 02:08PM

> for( auto i = l.begin();; ++i )
> { if( i != l.end() )::std::cout << *i << '\n';
> if( c++ > 20 )break; }}
 
Is ++i, when i equals l.end(), a well-defined operation ?
Bonita Montero <Bonita.Montero@gmail.com>: May 13 04:34PM +0200

> If you do a reserve() call with the final size before the insertion,
> it should work.
 
_Theoretically_ the first and last iterators of shouldn't "point" into
*this. But that's pure theory and I think the writers of the standard
were just to lazy to refine this statement with the cases where this
should actually work with any STL-implementation, i.e. when the capacity
is large enough and first and last are before the point where the insert
takes place.
"Öö Tiib" <ootiib@hot.ee>: May 13 07:49AM -0700

On Monday, 13 May 2019 17:08:28 UTC+3, Ike Naar wrote:
> > { if( i != l.end() )::std::cout << *i << '\n';
> > if( c++ > 20 )break; }}
 
> Is ++i, when i equals l.end(), a well-defined operation ?
 
AFAIK dereferencing or incrementing it is undefined
behavior always.
Decrementing it is well-defined operation when the
list is not empty.
% <persent@gmail.com>: May 12 02:38PM -0700

On 2019-05-12 2:36 p.m., Sir Gaygory's Owner's Owner 🐶笛 wrote:
> ✡✡✡✡✡✡✡✡✡✡✡ Often, posting code leads to an improvement.
> ✡✡✡✡✡✡✡✡✡✡✡
 
> using meaningful variable names to make your code actually readable, unless you're trying to win an obfuscated coding contest.
 
i take vitamin c when i get a code
Juha Nieminen <nospam@thanks.invalid>: May 13 09:41AM

> [Please do not mail me a copy of your followup]
 
Are we living in 1995?
"Öö Tiib" <ootiib@hot.ee>: May 13 02:38AM -0700

On Friday, 10 May 2019 14:26:22 UTC+3, Tim Rentsch wrote:
 
> I can't say anything about this without more specifics. I don't
> as of right now have any reason to think these unknown facts have
> any bearing on the issue.
 
I can be more specific.
For example .NET is defined to throw System.StackOverflowExeption
when it runs into stack limit.
 
> on things like system load, that makes the idea of a strictly
> conforming program pretty much meaningless. That contradiction
> is an excellent indication that something is wrong somewhere.
 
The whole issue is exactly that fully conforming C++ program is
allowed to be ran or not ran and when ran then to behave in
undefined manner when the resource limits are exceeded.
The resource limits of executing environment are nowhere
required to be constant nor checked or controlled and so it
may change from time to time like you describe. That is my
understanding of C++ standard and that matches with our
experiences as well.

 
> behavior is synonymous with any set of circumstances where the
> C++ standard (or the C standard) imposes no requirements on an
> implementation. But neither standard actually says that.
 
In my copy [defns.undefined] seems to say that:
undefined behavior - behavior for which this International Standard
imposes no requirements
 
UB seems to be defined to be that.
 
> in the two standards, I think you find that this view is more
> consistent and fits with everything they actually say related
> to definedness of behavior.
 
Yes, the whole issue (from what I had impression we started)
is that fully correct program is allowed to do whatever when the
unspecified resource limits of conforming implementation / execution
environment are exceeded.
jacobnavia <jacob@jacob.remcomp.fr>: May 13 08:19AM +0200

> Some people tried to label the Apostle Paul the same
> way. History concluded differently.
 
That will surely not be the case for you.
 
> I'm proud to live
> in St. Paul, Minnesota.
 
That's why you pretend to be the apostle st paul???
 
"History concluded differently" to put the great "woodbrian" in his
pedestal?
 
Vanity... All is vanity in this world.
 
> Side of History. How Reason and Moral Purpose Made the
> West Great" by Ben Shapiro.
> https://www.harpercollins.com/9780062857903/the-right-side-of-history/
 
Yeah, let's make the west great again... Sounds familiar.
 
 
> You are kind of out of the loop here I'm afraid.
 
You are in the loop. The loop of greed, religious nonsense, and a lot of
hypocrisy.
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: