[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.