lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Unexpected gcc diagnostic


From: Greg Chicares
Subject: Re: [lmi] Unexpected gcc diagnostic
Date: Wed, 7 Apr 2021 10:00:19 +0000
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0

On 4/6/21 6:59 PM, Greg Chicares wrote:
[...]
>> GC>     LMI_ASSERT(Bfts.begin() <= last_bft_in_test_period);
>> GC>     LowestBft = *std::min_element(Bfts.begin(), last_bft_in_test_period);
> 
> [...snip my rigorous proof of something that isn't quite what we want...]
> 
>>  All this is correct and holds even if Bfts vector is empty. However
>> dereferencing the iterator returned by std::min_element() wouldn't be in
>> this case, as it would return non-dereferencable Bfts.end() iterator. I'm
>> not at all sure if it's worth checking for this, but I wanted to at least
>> mention this for completeness.
> 
> Thanks: "<=" above isn't good enough; "<" would truly guard
> the "*std::min_element" expression.

No, I misunderstood. I tried making the change I described above:

-    LMI_ASSERT(Bfts.begin() <= last_bft_in_test_period);
+    LMI_ASSERT(Bfts.begin() < last_bft_in_test_period);

and that caused system-test failures.

The question is when it's okay to dereference this iterator:
  LowestBft = *std::min_element(Bfts.begin(), last_bft_in_test_period);
The answer is not whenever
  Bfts.begin() < last_bft_in_test_period
but, rather, whenever both
  Bfts.begin() < Bfts.end()               [the vector is not empty], and
  Bfts.begin() <= last_bft_in_test_period [the range is not insane]

Consider:
  std::vector<T> v;
  v.push_back(anything); // now 'v' is not empty
  auto subrange_end = v.begin(); // [v.begin(), subrange_end) is empty
  *std::min_element(v.begin(), subrange_end); // okay: same as v.front()

Generally we think of C++ iterator ranges as half-open intervals:
  [a,b) = {x | a ≤ x < b}
but if the endpoints are the same, then std::min_element treats the
interval as closed--as though it were [a,a] :
  [a,a] = {x | a ≤ x ≤ a} = {a}
according to [alg.min.max/26] ("Returns last if first == last").
Of course, that's a reasonable convention. Maybe it's even the only
reasonable convention to choose for std::min_element.

Maybe it's just the aftereffects of yesterday's surgery, but somehow
it troubles me to think that we have different empty sets that have
different minimums: if a≠b, then min [a,a) ≠ min [b,b) . I guess the
explanation is that viewing C++ iterator ranges as half-open is not
rigorous, when I had assumed it was.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]