Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Range-based for loops when you don't process everything in the container.

134 views
Skip to first unread message

Paul

unread,
Oct 31, 2018, 10:34:54 AM10/31/18
to
Below is my code for determining if a given sequence of distinct
integers has a decreasing subsequence of length 3.
Is there a standard range-based approach for writing for(int i = 2; i < x.size(); ++ i)

Thanks. (Of course, any comments on the code are welcome.) I'd be surprised
if it's wrong because I've tested it quite a bit.

Paul

// A permutation being a riffle shuffle is equivalent to there being no decreasing
// subsequence of length 3. All cards are assumed distinct.
bool isRiffleShuffle(const std::vector<int>& cards)
{
if(cards.size() < 3)
return true;

// Keep track of the "largest" decreasing subsequence of length 2
// and whether such a sequence exists.
int maximum = std::max(cards[0], cards[1]);
int afterPeak;
bool decreasing2 = cards[1] < cards[0];
if(decreasing2)
afterPeak = cards[1];

for(int i = 2; i < cards.size(); ++i)
{
const int card = cards[i];
if(decreasing2 && card < afterPeak)
return false;

if(card > maximum)
maximum = card;
else
{
if(!decreasing2 || card > afterPeak)
afterPeak = card;
decreasing2 = true;
}
}
return true;
}

Alf P. Steinbach

unread,
Oct 31, 2018, 11:17:18 AM10/31/18
to
On 31.10.2018 15:34, Paul wrote:
> Below is my code for determining if a given sequence of distinct
> integers has a decreasing subsequence of length 3.
> Is there a standard range-based approach for writing for(int i = 2; i < x.size(); ++ i)

Not yet, as far as I know. But see below.

Before getting to that, however, I suggest compiling with the highest
practical warning levels. For g++ (and presumably clang, since it was
designed as drop-in replacement) that means `-Wall -pedantic-errors
-std=c++17`, and for Visual C++ 2017 (and presumably Intel, ditto) that
means `/W4 /D _CRT_SECURE_NO_WARNINGS /D _STL_SECURE_NO_WARNINGS`.

Then you'd discover that the following way of writing the loop,

for( int i = 2, n = cards.size(); i < n; ++i )

... both avoids warnings and guarantees performance.

>
> Thanks. (Of course, any comments on the code are welcome.) I'd be surprised
> if it's wrong because I've tested it quite a bit.
>
> Paul
>
> // A permutation being a riffle shuffle is equivalent to there being no decreasing
> // subsequence of length 3. All cards are assumed distinct.
> bool isRiffleShuffle(const std::vector<int>& cards)
> {
> if(cards.size() < 3)
> return true;
>
> // Keep track of the "largest" decreasing subsequence of length 2
> // and whether such a sequence exists.
> int maximum = std::max(cards[0], cards[1]);
> int afterPeak;
> bool decreasing2 = cards[1] < cards[0];
> if(decreasing2)
> afterPeak = cards[1];
>
> for(int i = 2; i < cards.size(); ++i)
> {
> const int card = cards[i];
> if(decreasing2 && card < afterPeak)

Visual C++ 2017 with `/W4` says,

p:\temp\foo.cpp(22) : warning C4701: potentially uninitialized local
variable 'afterPeak' used

Upping the warning level can be really useful, not just for writing
loops with efficient execution, but also for correctness.

> return false;
>
> if(card > maximum)
> maximum = card;
> else
> {
> if(!decreasing2 || card > afterPeak)
> afterPeak = card;
> decreasing2 = true;
> }
> }
> return true;
> }


---------------------------------------------------------------------
#include <algorithm>
#include <vector>

struct Start_offset{ int value; };

template< class It >
class It_range
{
It m_first;
It m_after;

public:
auto begin() const -> It { return m_first; }
auto end() const -> It { return m_after; }

It_range( const It first, const It after ):
m_first( first ),
m_after( after )
{}

It_range( const It first, const It after, const Start_offset offset
= {0} ):
m_first( first + offset.value ),
m_after( after )
{}
};

#include <iostream>
#include <iterator> // std::(begin, end)
#include <numeric> // std::iota
#define $items( c ) std::begin( *&c ), std::end( c )
auto main()
-> int
{
using namespace std;

vector<int> cardinals( 7 );
iota( $items( cardinals ), 1 );

// Output "3 4 5 6 7".
// Using C++17 template parameter deduction from constructor args.
for( const int i : It_range( $items( cardinals ), Start_offset{ 2 } ) )
{
cout << i << ' ';
}
cout << endl;
}
---------------------------------------------------------------------


Cheers!,

- Alf

Alf P. Steinbach

unread,
Oct 31, 2018, 11:20:12 AM10/31/18
to
On 31.10.2018 16:17, Alf P. Steinbach wrote:
>
>     It_range( const It first, const It after, const Start_offset offset
> = {0} ):
>         m_first( first + offset.value ),
>         m_after( after )
>     {}
> };

Oh, instead of `+` should use whatever that std:: function is called,
that behaves appropriately for random access and forward iterators.

Sorry,

- Alf

Ralf Goertz

unread,
Oct 31, 2018, 11:24:00 AM10/31/18
to
Am Wed, 31 Oct 2018 07:34:33 -0700 (PDT)
schrieb Paul <peps...@gmail.com>:
"afterPeak" is not initialized if cards[1]>cards[0]. BTW does that mean
it is 0? Seems not to be the case since using "g++ -O6 -Wall" on the
following program always prints 1 regardless of the value of argc but it
doesn't warn about ‘x’ being used uninitialized.


#include <iostream>

int main(int argc, char *argv[]) {
int x;
if (argc>1) x=1;
std::cout<<x<<"\n";
}

Ralf Goertz

unread,
Oct 31, 2018, 11:35:44 AM10/31/18
to
Am Wed, 31 Oct 2018 16:17:02 +0100
schrieb "Alf P. Steinbach" <alf.p.stein...@gmail.com>:

> Before getting to that, however, I suggest compiling with the highest
> practical warning levels. For g++ (and presumably clang, since it was
> designed as drop-in replacement) that means `-Wall -pedantic-errors
> -std=c++17`, and for Visual C++ 2017 (and presumably Intel, ditto)
> that means `/W4 /D _CRT_SECURE_NO_WARNINGS /D
> _STL_SECURE_NO_WARNINGS`.

Hm, in the example given in my answer to the op g++ remains silent with
"g++ -Wall -pedantic-errors". Using -O0 prints 0 using -O2 prints 1 when
argc is 1.

#include <iostream>

int main(int argc, char *argv[]) {
int x;
if (argc>1) x=1;
std::cout<<x<<" "<<argc<<"\n";
}

Paul

unread,
Oct 31, 2018, 11:53:30 AM10/31/18
to
afterPeak is only relevant when decreasing2 is true and afterPeak is only
used when decreasing2 is true. However, it is correct that the compiler
doesn't know that no uninitialised variables are being read.
When I tested a few minutes ago, afterPeak was initialised to 7274116 rather
than 0.

I don't see a problem here.

Paul

Scott Lurndal

unread,
Oct 31, 2018, 12:12:15 PM10/31/18
to
Ralf Goertz <m...@myprovider.invalid> writes:
>Am Wed, 31 Oct 2018 07:34:33 -0700 (PDT)
>schrieb Paul <peps...@gmail.com>:

>#include <iostream>
>
>int main(int argc, char *argv[]) {
> int x;
> if (argc>1) x=3D1;
> std::cout<<x<<"\n";
>}
>

The initial value of 'x' is simply whatever value is in
memory at the stack location assigned to x. This may often
be zero, but is not guaranteed to be (e.g. if a bunch of
shared objects are loaded in the crt before calling 'main',
then it's likely that 'x' is reusing a memory location).

Louis Krupp

unread,
Oct 31, 2018, 4:06:56 PM10/31/18
to
On Wed, 31 Oct 2018 07:34:33 -0700 (PDT), Paul <peps...@gmail.com>
wrote:
Note that decreasing2, once set to true, is never set to false.

There's a simpler (or at least shorter) way to do it that lets you use
a range-based for loop:

===
#include <iostream>
#include <limits>
#include <vector>

bool IsRiffleShuffle(const std::vector<int>& cards)
{
auto n_decreasing = 0;
auto prev_card = std::numeric_limits<int>::min();

for (auto card : cards) {
if (card < prev_card) {
// Two decreasing cards indicates a decreasing subsequence
// of 3
if (++n_decreasing == 2)
return false;
} else
n_decreasing = 0;
prev_card = card;
}

return true;
}

int main()
{
std::cout << std::boolalpha << IsRiffleShuffle({}) << "\n";
std::cout << std::boolalpha << IsRiffleShuffle({1, 2, 3}) << "\n";
std::cout << std::boolalpha << IsRiffleShuffle({3, 2, 1}) << "\n";
std::cout << std::boolalpha << IsRiffleShuffle({3, 2, 2}) << "\n";
std::cout << std::boolalpha << IsRiffleShuffle({3, 4, 2}) << "\n";
}
===

Richard

unread,
Oct 31, 2018, 4:16:38 PM10/31/18
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<prch1f$1c7$1...@dont-email.me> thusly:

>Then you'd discover that the following way of writing the loop,
>
> for( int i = 2, n = cards.size(); i < n; ++i )
>
>... both avoids warnings and guarantees performance.

Is the performance claim really legitimate?

Is there any compiler that isn't going to lift this loop
invariant out of the loop for you when optimizations are turned on?

I find doing this just makes the code less clear and introduces a
variable that can be accidentally (or "cleverly") modified when you
didn't intent for it to be modified.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Terminals Wiki <http://terminals-wiki.org>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Alf P. Steinbach

unread,
Nov 1, 2018, 12:58:16 AM11/1/18
to
On 31.10.2018 21:16, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
> <prch1f$1c7$1...@dont-email.me> thusly:
>
>> Then you'd discover that the following way of writing the loop,
>>
>> for( int i = 2, n = cards.size(); i < n; ++i )
>>
>> ... both avoids warnings and guarantees performance.
>
> Is the performance claim really legitimate?

It guarantees a single call of the `size` function. The compiler might
be able to do that on its own, or not. There's no guarantee of
optimization of the original loop, because it depends on whether the
compiler is smart enough to see that no operation modifies the vector.


> Is there any compiler that isn't going to lift this loop
> invariant out of the loop for you when optimizations are turned on?

Don't know, sorry.


> I find doing this just makes the code less clear

I seldom find naming to make code less clear, provided the names are
reasonably descriptive. On the contrary, not naming things tends to
create an unclear mess. `n` is self-explanatory to my eyes, YMMV. :)


> and introduces a
> variable that can be accidentally (or "cleverly") modified when you
> didn't intent for it to be modified.

One can make `n` const if it's declared before the loop.

Technically one can do that also within the loop, but it's ugly.

I coded up some examples:


#include <stddef.h> // ptrdiff_t

template< class Type >
auto dummy_use( const Type& ) -> bool { return true; }

#define $with( ... ) if( const auto& _ = __VA_ARGS__; dummy_use( _ ) ||
true )

template< class Container >
auto n_items( const Container& c )
-> ptrdiff_t
{ return size( c ); }

struct Iter{ const int n; int i; };

class Up_to
{
const int my_n;
public:
template< class F >
void perform( const F& f )
{
for( int i = 0; i < my_n; ++i ) { f( i ); }
}

Up_to( const int n ): my_n( n ) {}
};


#include <iostream>
#include <vector>
#include <iterator> // std::size
using namespace std;

auto main()
-> int
{
const vector<int> numbers = {1, 2, 3, 4, 5};

// Original code, just modified to avoid signed/unsigned warning/bugs.
for( int i = 0; i < n_items( numbers ); ++i )
{
cout << numbers[i] << ' ';
}
cout << endl;

// Near idiomatic.
for( int i = 0, n = n_items( numbers ); i < n; ++i )
{
cout << numbers[i] << ' ';
}
cout << endl;

// "Safe" version of the above loop. But IMHO it's just silly.
for( int i = 0, n = n_items( numbers ); i < n; ++i )
{
void n(); // The safety, code below can't change `n`.
cout << numbers[i] << ' ';
}
cout << endl;

// Safe and conventional details, but "leaks" `n` to rest of scope.
const int n = n_items( numbers );
for( int i = 0; i < n; ++i )
{
cout << numbers[i] << ' ';
}
cout << endl;

// Addresses the leakage of a no-purpose name by using "_" as name.
$with( n_items( numbers ) ) for( int i = 0; i < _; ++i )
{
cout << numbers[i] << ' ';
}
cout << endl;

// A silly way to have `n` const and all variables local to the loop.
for( Iter L{ int( n_items( numbers ) ) }; L.i < L.n; ++L.i )
{
cout << numbers[L.i] << ' ';
}
cout << endl;

// Not so sure if this is silly, over-engineering, or actually useful?
Up_to( n_items( numbers ) ).perform( [&]( const int i )
{
cout << numbers[i] << ' ';
} );
cout << endl;

cout << "Finished!" << endl;
}


Cheers!,

- Alf

James Kuyper

unread,
Nov 1, 2018, 7:39:57 AM11/1/18
to
On 11/1/18 00:58, Alf P. Steinbach wrote:
> On 31.10.2018 21:16, Richard wrote:
>> [Please do not mail me a copy of your followup]
>>
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
>> <prch1f$1c7$1...@dont-email.me> thusly:
>>
>>> Then you'd discover that the following way of writing the loop,
>>>
>>> for( int i = 2, n = cards.size(); i < n; ++i )
>>>
>>> ... both avoids warnings and guarantees performance.
>>
>> Is the performance claim really legitimate?
>
> It guarantees a single call of the `size` function. The compiler might
> be able to do that on its own, or not. There's no guarantee of
> optimization of the original loop, because it depends on whether the
> compiler is smart enough to see that no operation modifies the vector.

For loops in general (not just this particular code), if the compiler
can't see that no operation modifies the vector, that might be because
the loop contains some code which does modify the vector. If that were
the case, using n rather than cards.size() could have really nasty
consequences.

Alf P. Steinbach

unread,
Nov 1, 2018, 9:01:47 AM11/1/18
to
You're saying, if the code is incorrect you'd rather give it the best
possible shot of not crashing or producing obviously wrong result?

Hm!


Cheers!,

- Alf

james...@alumni.caltech.edu

unread,
Nov 1, 2018, 10:10:06 AM11/1/18
to
No, I was talking about code which uses

for(int i=2; i < cards.size(); i++)

to control a loop body that can, under some circumstances, cause
cards.size() to change, and which deals correctly with that
possibility. The simplest case is that it might add cards to the
end of the container, but it's entirely feasible for such a loop
to delete cards or insert them anywhere in the container,
possibly requiring that the body of the loop change the value of
i. It's easy for code with such features to be written
incorrectly; it requires careful attention to write such code
correctly. However, the presence of such features does not, in
itself, guarantee that the code is incorrect. And if you change
such code to use for( int i = 2, n = cards.size(); i < n; ++i ),
it will become incorrect.

Richard

unread,
Nov 1, 2018, 12:44:07 PM11/1/18
to
[Please do not mail me a copy of your followup]

James Kuyper <james...@alumni.caltech.edu> spake the secret code
<preom1$j7o$1...@dont-email.me> thusly:
This question seems to be an obvious situation to use compiler
explorer.

When I compile with no optimizations, I see calls to size().

When I compile with -O1 or -O2 I don't see calls to size(), I see a
simple increment and compare.

WHen I compile with -O3, it starts using SSE vectorization on the loop
and things get "longer".

<https://godbolt.org/z/PkCT2L>

Marcel Mueller

unread,
Nov 1, 2018, 2:52:13 PM11/1/18
to
Am 31.10.2018 um 15:34 schrieb Paul:
> Below is my code for determining if a given sequence of distinct
> integers has a decreasing subsequence of length 3.
> Is there a standard range-based approach for writing for(int i = 2; i < x.size(); ++ i)

Some containers provide virtual slices that refer to subsections of the
original container. But the standard containers AFAIK do never.

However, I would rather use a more elegant algorithm:

#include <algorithm>
#include <numeric>
#include <vector>
#include <iostream>

int main()
{
std::vector<int> cards { 5,9,2,3,5,4,8,3,2,4,5,6,2,9 };
std::adjacent_difference(cards.begin(), cards.end(), cards.begin(),
std::less<int>{});
std::cout << (cards.end() != std::adjacent_find(cards.begin()+1,
cards.end(), std::logical_and<int>{}));
return 0;
}

Unfortunately this algorithm needs a temporary storage since C++ does
not provide stream operations like Java or .NET.


Marcel

Juha Nieminen

unread,
Nov 1, 2018, 3:11:00 PM11/1/18
to
Alf P. Steinbach <alf.p.stein...@gmail.com> wrote:
> You're saying, if the code is incorrect you'd rather give it the best
> possible shot of not crashing or producing obviously wrong result?

What he is saying is that if the code is modified so that it changes
the size of the vector, it will start misbehaving.

Jorgen Grahn

unread,
Nov 1, 2018, 3:46:07 PM11/1/18
to
On Wed, 2018-10-31, Paul wrote:
> Below is my code for determining if a given sequence of distinct
> integers has a decreasing subsequence of length 3.

> // A permutation being a riffle shuffle is equivalent to there being
> no decreasing // subsequence of length 3. All cards are assumed
> distinct.

> bool isRiffleShuffle(const std::vector<int>& cards)
> {

One observation: since the problem is about a deck of cards rather
than a vector<int>, when you get the latter working you could
generalize it to:

template<class Card>
bool isRiffleShuffle(const std::vector<Card>&);

and then to:

template<class ForwardIterator>
bool isRiffleShuffle(ForwardIterator begin,
ForwardIterator end);

Perhaps I'm contradicting myself here, since earlier I argued against
generalizing too early. But in a real application, I'd hate to
convert my deck of cards to ints to be able to tell if they're
decently shuffled.

/Jorgen

--
// jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

james...@alumni.caltech.edu

unread,
Nov 1, 2018, 4:24:35 PM11/1/18
to
No, that's not what I'm saying.

First, let me make it clear that the code I'm talking about is NOT the
particular function that Paul was talking about in his original message.
It's hypothetical code containing a similarly controlled loop that is
correctly written to perform an unspecified task, one that requires
either adding items to or removing items from the vector, possibly both.

What I'm saying is that changing the loop controls in such code to use
i < n rather than i < cards.size() could cause it to start misbehaving.
It might either terminate before processing all elements of the vector,
or attempt to access a non-existent element of the vector.

Öö Tiib

unread,
Nov 1, 2018, 5:11:10 PM11/1/18
to
That is correct both ways. Also code that did work correctly with
"for (int i = 2, n = cards.size(); i < n; ++i)" could become silently
incorrect after changing to "for (int i = 2; i < cards.size(); i++)".
Hypothetical body of hypothetical loop is such a blurred thing.

Vir Campestris

unread,
Nov 1, 2018, 5:19:21 PM11/1/18
to
On 31/10/2018 15:23, Ralf Goertz wrote:
> "afterPeak" is not initialized if cards[1]>cards[0]. BTW does that mean
> it is 0?

No.

It's what that bit of memory was last used for.

Are you feeling lucky?

Andy

James Kuyper

unread,
Nov 1, 2018, 9:00:43 PM11/1/18
to
On 11/1/18 17:10, Öö Tiib wrote:
> On Thursday, 1 November 2018 22:24:35 UTC+2, james...@alumni.caltech.edu wrote:
...
>> First, let me make it clear that the code I'm talking about is NOT the
>> particular function that Paul was talking about in his original message.
>> It's hypothetical code containing a similarly controlled loop that is
>> correctly written to perform an unspecified task, one that requires
>> either adding items to or removing items from the vector, possibly both.
>>
>> What I'm saying is that changing the loop controls in such code to use
>> i < n rather than i < cards.size() could cause it to start misbehaving.
>> It might either terminate before processing all elements of the vector,
>> or attempt to access a non-existent element of the vector.
>
> That is correct both ways. Also code that did work correctly with
> "for (int i = 2, n = cards.size(); i < n; ++i)" could become silently
> incorrect after changing to "for (int i = 2; i < cards.size(); i++)".
> Hypothetical body of hypothetical loop is such a blurred thing.

Perhaps you could construct an example for which that is true, but only
by reason of my failure to explicitly specify what I thought was
obvious: the intent is to iterate over all the elements in the container
except the first 2. If that's the goal, then

for (int i = 2; i < cards.size(); i++)

is unambiguously a correct way of doing it, regardless of whether
cards.size() might change during the loop, while

for (int i = 2, n = cards.size(); i < n; ++i)

is correct only as an optimization that depends upon assuming that
cards.size() won't be changing, unless n is changed inside the body of
the loop whenever the size changes (which would be a pretty inefficient
way of doing things).


James Kuyper

unread,
Nov 1, 2018, 9:04:25 PM11/1/18
to
On 11/1/18 14:52, Marcel Mueller wrote:
...
> Some containers provide virtual slices that refer to subsections of the
> original container. But the standard containers AFAIK do never.

See std::slice, std::slice_array, std::gslice, and std::gslice_array
described in 26.6.4-7.

Ralf Goertz

unread,
Nov 2, 2018, 4:48:28 AM11/2/18
to
Am Thu, 1 Nov 2018 21:19:10 +0000
schrieb Vir Campestris <vir.cam...@invalid.invalid>:
Not particulary, I always assumed that to be the case but I was
surprised to see that g++ doesn't warn about uninitialised variables in
cases like this:

#include <iostream>

int main(int argc, char *argv[]) {
int x;
if (argc>1) x=1;
std::cout<<x<<"\n";
}

I thought maybe the rules had changed recently. That's why I asked.

Öö Tiib

unread,
Nov 2, 2018, 4:51:18 AM11/2/18
to
That logic assumes some subset of conceivable algorithms. Example:
Let's suppose there is an algorithm that processes all elements in
sequence. During that processing it may add elements to end of
sequence.
When it should process also the freshly added elements then first
for header is correct. When it should not process those then second
header is correct. When we know that processing freshly added
elements will cause no changes in result then both are correct but
second is more efficient.

Manfred

unread,
Nov 2, 2018, 11:41:40 AM11/2/18
to
On 11/2/2018 9:48 AM, Ralf Goertz wrote:
> Not particulary, I always assumed that to be the case but I was
> surprised to see that g++ doesn't warn about uninitialised variables in
> cases like this:
>
> #include <iostream>
>
> int main(int argc, char *argv[]) {
> int x;
> if (argc>1) x=1;
> std::cout<<x<<"\n";
> }
>
> I thought maybe the rules had changed recently. That's why I asked.

If you change it into:
int main(int argc, char *argv[])
{
int x;
if (argc>2) x=1;
else if (argc>1) x=2;
std::cout << x << "\n";
}

Then c++ -O2 -Wall will issue the warning
man gcc says that -Wmaybe-uninitialized is active only with optimized
compilation, I can't say why the single if is silently passed (I am
smelling some kind of UB stuff though)

james...@alumni.caltech.edu

unread,
Nov 2, 2018, 11:59:54 AM11/2/18
to
The basic principle here is that gcc does a much more careful analysis
of the code when you select higher optimization levels. At low
optimization levels it saves a lot of time by not doing that analysis.
It doesn't even notice that the variable's value might be used when it
hasn't been initialized until it's done that analysis. The flip side is
that, at low optimization levels, if it has behavior you don't want it
to have, it will have that behavior only because the memory being read
has unpredictable contents, not because of any more esoteric problem due
to interacting with an optimization.

Manfred

unread,
Nov 2, 2018, 12:13:41 PM11/2/18
to
True, the manpage says that without optimizing compilation "GCCdoes not
keep track of the state of variables"

> It doesn't even notice that the variable's value might be used when it
> hasn't been initialized until it's done that analysis. The flip side is
> that, at low optimization levels, if it has behavior you don't want it
> to have, it will have that behavior only because the memory being read
> has unpredictable contents, not because of any more esoteric problem due
> to interacting with an optimization.
>
Still this does not explain why the warning is not issued unless the
conditional has more than one branch.
My gut feeling about UB is based on the fact that the conditional seems
to be skipped if there is only a single branch (if you change the
assignment value in the conditional, that value seems to be output), but
this would assume UB territory.
Still according to the manpage the warning should occur, unless I am
missing something.

Manfred

unread,
Nov 2, 2018, 1:12:50 PM11/2/18
to
On 10/31/2018 4:17 PM, Alf P. Steinbach wrote:
> Before getting to that, however, I suggest compiling with the highest
> practical warning levels. For g++ (and presumably clang, since it was
> designed as drop-in replacement) that means `-Wall -pedantic-errors
> -std=c++17`, and for Visual C++ 2017 (and presumably Intel, ditto) that
> means `/W4 /D _CRT_SECURE_NO_WARNINGS /D _STL_SECURE_NO_WARNINGS`.

Actually /D _CRT_SECURE_NO_WARNINGS /D _STL_SECURE_NO_WARNINGS (was it
meant to be _S*C*L_SECURE_NO_WARNINGS ?) in VC++ /loosen/ the warning
level instead of enhancing it with respect to the default.

It is true, however, that they suppress a number of warning about C and
C++ APIs that are perfectly legal according to the standard, but that MS
has decided to 'deprecate' because 'insecure' (in the hands of the naive
programmer, I would add)
So what to suggest as recommended settings? In VS having those #defines
in place allows for full usage of the standard library facilities
without compiler noise, but requires some care by the programmer.
Leaving them out yields some protection against programing errors, but
restricts some use of such facilities.
I guess your suggestion was motivated by the former standpoint.

Alf P. Steinbach

unread,
Nov 2, 2018, 2:12:49 PM11/2/18
to
On 02.11.2018 18:12, Manfred wrote:
> On 10/31/2018 4:17 PM, Alf P. Steinbach wrote:
>> Before getting to that, however, I suggest compiling with the highest
>> practical warning levels. For g++ (and presumably clang, since it was
>> designed as drop-in replacement) that means `-Wall -pedantic-errors
>> -std=c++17`, and for Visual C++ 2017 (and presumably Intel, ditto)
>> that means `/W4 /D _CRT_SECURE_NO_WARNINGS /D _STL_SECURE_NO_WARNINGS`.
>
> Actually /D _CRT_SECURE_NO_WARNINGS /D _STL_SECURE_NO_WARNINGS (was it
> meant to be _S*C*L_SECURE_NO_WARNINGS ?) in VC++ /loosen/ the warning
> level instead of enhancing it with respect to the default.

They're utterly impractical warnings, designed for Microsoft programmers
who use the C++ compiler as essentially a C compiler. So a practical
warning level with Visual C++ is to turn off the idiocy. IMHO.


> It is true, however, that they suppress a number of warning about C and
> C++ APIs that are perfectly legal according to the standard, but that MS
> has decided to 'deprecate' because 'insecure' (in the hands of the naive
> programmer, I would add)
> So what to suggest as recommended settings? In VS having those #defines
> in place allows for full usage of the standard library facilities
> without compiler noise, but requires some care by the programmer.

Yes.


> Leaving them out yields some protection against programing errors, but
> restricts some use of such facilities.
> I guess your suggestion was motivated by the former standpoint.

Yes.


Cheers!,

- Alf

Richard

unread,
Nov 2, 2018, 5:00:19 PM11/2/18
to
[Please do not mail me a copy of your followup]

James Kuyper <james...@alumni.caltech.edu> spake the secret code
<prg7qg$ug5$1...@dont-email.me> thusly:
They only work with valarrays, so they're not useful for arbitrary
containers.

Manfred

unread,
Nov 3, 2018, 1:16:19 PM11/3/18
to
On 11/2/2018 4:59 PM, james...@alumni.caltech.edu wrote:
This happens to be a long known bug in gcc:
https://gcc.gnu.org/PR18501

Jorgen Grahn

unread,
Nov 7, 2018, 6:47:54 AM11/7/18
to
On Wed, 2018-10-31, Paul wrote:
> Below is my code for determining if a given sequence of distinct
> integers has a decreasing subsequence of length 3.
...

This is in the wrong thread; it's a followup to when Mr Tiib
recommended doing exercises (like you now do). One I've heard good
things about is this:

https://adventofcode.com/

Friends and coworkers followed it in December last year.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .

Alf P. Steinbach

unread,
Nov 7, 2018, 8:08:28 AM11/7/18
to
On 07.11.2018 12:47, Jorgen Grahn wrote:
> On Wed, 2018-10-31, Paul wrote:
>> Below is my code for determining if a given sequence of distinct
>> integers has a decreasing subsequence of length 3.
> ...
>
> This is in the wrong thread; it's a followup to when Mr Tiib
> recommended doing exercises (like you now do). One I've heard good
> things about is this:
>
> https://adventofcode.com/
>
> Friends and coworkers followed it in December last year.

Well, I started with the 2015 challenges, the warm-up section I believe
it was, and at first got a wrong answer. Because my copy-paste of the
data omitted the last line. But with that corrected, right answer to
part 1, I then gpt a "too high" answer of 1798 to the part 2 question.

The question is, when you start with 0, add 1 for each "(", and subtract
1 for each ")", what's the character position of the first character
that produces -1 for you? E.g., from the puzzle text,

<quote>
) causes him to enter the basement at character position 1.
()()) causes him to enter the basement at character position 5.
</quote>

The input data is available at <url:
https://adventofcode.com/2015/day/1/input>.

My code, before I figured out my error:

#include <iostream>
#include <stdlib.h>
using namespace std;

auto main()
-> int
{
int floor = 0;
char c;
int position = 0;
while( cin >> c )
{
++position;
floor += (c == '('? +1 : c == ')'? -1 : 0);
if( floor == -1 )
{
cout << position << endl;
return EXIT_SUCCESS;
}
}
return EXIT_FAILURE;
}

This code worked nicely for the examples given above, with the text
piped to it from `echo` commands, and since the input data has no
newlines and no spaces or anything, I didn't see where I went wrong?

--- spoiler below --







































Well, as it turned out, the UTF-8 BOM that's so necessary in Windows, 3
character codes at the start of the file. It's my own fault for creating
an ¹extension for Notepad++ that sets the default encoding for new text
files to UTF-8 with BOM. Idiot! :( :( :(

Oh, changing the text file format worked, and completed day 1! :) I
think now I'll have breakfast. Too long postponed.


Cheers!,

- Alf


Notes:

¹ <url:
https://github.com/alf-p-steinbach/NPP-plugin-Empty-files-as-Unicode>
0 new messages