- Preprocessor proposal for C and C++ - 5 Updates
- newbie question: insert a vector to itself at end - 16 Updates
- Posting code leads to an improvement. - 1 Update
- Replace raw loop with std::algorithm - 1 Update
- Undefined Behaviour - 1 Update
- Now what? - 1 Update
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:
Post a Comment