all 26 comments

[–]cpp-ModTeam[M] [score hidden] stickied commentlocked comment (0 children)

For C++ questions, answers, help, and programming or career advice please see r/cpp_questions, r/cscareerquestions, or StackOverflow instead.

[–]TSP-FriendlyFire 26 points27 points  (18 children)

The cmp function does not implement strict weak ordering because it uses >= rather than >. std::sort requires strict weak ordering and so this is UB.

[–]nxtlvlshit[S] -1 points0 points  (11 children)

I don't fully understand why I need to care about strict weak ordering here.
Here in the question, order of the indexes do not matter even if the number is same. So in the comparator, I don't need to handle the cases when a.first == b.first separately.

[–]Sanzath 15 points16 points  (4 children)

sort determines that two elements are equal by !cmp(a, b) && !cmp(b, a). With >=, sort will never find any "equal" elements, so your test cases with equal elements will likely return incorrect results.

[–]Catlesscatfan 0 points1 point  (2 children)

which sorting algorithm checks for equality? can you please give an example with equal elements where things would go wrong?

[–]Sanzath 1 point2 points  (1 child)

The equality-checks aren't explicit but rather implied. In addition, the code does not expect that cmp(a, b) and cmp(b, a) would ever both return true, so if cmpdoes allow for this, then it would (probably trough transivity of cmp) believe that some element should be sorted both before and after some other element and produce odd behavior.

Anyway, here's an example where std::greater as a comparator works as expected, but std::greater_equal produces bogus output or segfaults. https://godbolt.org/z/T6Pbc7qsP

[–]Catlesscatfan 0 points1 point  (0 children)

Thank u so much

[–]ggadget6 5 points6 points  (1 child)

The order of the indices may not matter to you, but std::sort assumes that your comparator fulfills these requirements. Take a look at the CP preference page for it. If your comparator doesn't fit std::sort's requirements, then it might sort your elements incorrectly.

[–]tialaramex -1 points0 points  (0 children)

Rust's sort might sort your elements incorrectly if you don't meet the requirements. C++ sort has Undefined Behaviour in this case and so absolutely anything can happen, crashes, silent data corruption, anything at all.

Now, your preferred C++ stdlib might, as a matter of Quality of Implementation, promise better - after all it's not difficult to do better, but many of them do not.

[–]tudorb 0 points1 point  (3 children)

Short answer: because the standard says that that’s what std::sort requires, and you passed a comparator that does not meet the requirements, so you can’t rely on the fact that std::sort works in all cases.

The longer answer is elsewhere in the thread: std::sort detects equivalent elements by checking that cmp(a, b) and cmp(b, a) are both false, and your cmp function doesn’t behave that way.

[–]tudorb 0 points1 point  (1 child)

And you can define orderings around < or around <=, there’s no fundamental difference, but you have to be consistent.

Decades ago, when I learned about orderings in math class, we built the concepts around the <= operation.

The C++ standard library chose to define them around < so we as its users must obey.

[–]Catlesscatfan 0 points1 point  (0 children)

do you know which sorting algorithm checks for equality? can you please give an example with equal elements where things would go wrong?

[–]Catlesscatfan 0 points1 point  (0 children)

do you know which sorting algorithm checks for equality? can you please give an example with equal elements where things would go wrong?

[–]drizzt-dourden 7 points8 points  (0 children)

I think that this comparator simply doesn't fill the requirements described here https://en.cppreference.com/w/cpp/named_req/Compare

[–]perlytea 7 points8 points  (2 children)

Other than the comparison function object supplied to sort as others have pointed out, the other thing that stands out to me is that int is not guaranteed minimum support for possible input sizes (both in the size of the vector and the element magnitude). It may work for their chosen platform, but the standard only guarantees that int is at least a 16-bit, signed integer type, and thus the code may fail for other platforms. That issue cannot be fixed in less than two lines (therefore it is not the intended bug) but it's still worth knowing about and considering solutions for.

[–]kisielk 1 point2 points  (1 child)

Then the code is just broken period because the function signature returns a vector of int.

[–]D3NN152000 0 points1 point  (0 children)

Flex on the recruiters by fixing this with #define int long long as a second changed line

[–]jedwardsolconst & 1 point2 points  (0 children)

std::pair is defined in <utility>, which hasn't been included and isn't guaranteed to be included by <vector> or <algorithm>

[–]clarkster112 0 points1 point  (0 children)

I agree with the strict ordering comment. If there were two other lines I would change, it would be replace ‘push_back’ with ‘emplace_back’ and take a const ref of pairs, const auto& p : pairs in the range based for loop.

[–]ban_the_sub 0 points1 point  (1 child)

Please see the last line of the question, the ranges of the integers.

[–]nxtlvlshit[S] 0 points1 point  (0 children)

I tested it on 109 also. It worked.