0

Consider following snippet:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int x=3;
    int y=1;
    int z=2;
    cout<<(&x)<<' '<<(&y)<<' '<<(&z)<<endl;
    set<reference_wrapper<int>> a;
    a.insert(ref(x));
    a.insert(ref(y));
    a.insert(ref(z));
    for(const auto& i: a) cout<<i<<' '<<endl;
    y=10;
    for(const auto& i: a) cout<<i<<' ';
    return 0;
}

What would happen to underlying container when a property used by container for sorting is modified?


Edit1 : From what I can try by running code, ordering goes wrong but since it was holding a reference, value is correctly updated. So one should be careful when using reference_wrapper inside containers (specially where mutations can cause container to invalidate its assertions)?

9
  • 3
    you managed to break an invariant. Keys in std::set are supposed to be const. As with almost anything there are ways to bypass this restriction but what you get is a broken set. Commented Jul 9, 2024 at 9:18
  • concerning your "Edit1" please try to keep the quesiton concise. SO is not like a forum with back and forth discussion. It shouldnt be necessary to read the quesiton, read the answer, continue to read the question to grasp what is being asked here. Commented Jul 9, 2024 at 9:20
  • 1
    thats the actually interesting part of the quesiton to which I also do not have an answer. Note that std::set provides you no non-const access to the elements. std::set::iterator is a constant iterator. Further note that you are not actually modifying the elements, they are const, but you modify the objects they refer to. The issue is with the comparator. I am not aware of some formalism that requires that when you do auto x = comp(a,b);, do something (but not insert nor remove elements), auto y = comp(a,b); that x and y must be the same. Commented Jul 9, 2024 at 9:51
  • 1
    but someone else knows :D Commented Jul 9, 2024 at 9:52
  • 2
    Where did you learn #include <bits/stdc++.h>? Block that site. Burn that book. Unfriend that friend. Learn C++ from a good C++ book. Commented Jul 9, 2024 at 11:12

1 Answer 1

4

What would happen to underlying container when a property used by container for sorting is modified?

Any further use of the container, that requires the comparison of that element, has undefined behaviour, because you are violating this requirement:

For any two keys k1 and k2 in the same container, calling comp(k1, k2) shall always return the same value.

[associative.reqmts.general]

Sign up to request clarification or add additional context in comments.

13 Comments

Got it, thanks! How can one avoid getting into these issue? Should we avoid using reference_wrapper in keys of associative containers and unordered associative containers?
If the answer to above is yes, then, shouldn't standard only should not allow it to be created in first place? One can be careful but I think it might be much easier to run into this issue in a large codebase.
@Rupa std::reference_wrapper is not magic. Anyone can create similar classes. The key principle is not to create dangling references. Current state of C++ cannot prevent user from doing that.
@Rupa If the standard blocked std::reference_wrapper in sets, then someone would just write lib::reference_wrapper. To block that, you'd have to ban any class with any pointer data members. You just have to be vigilant about modification
@Red.Wave but the question is not about dangling reference. Sure there can be issues OP didnt encounter yet, and being aware of dangling references is important. Your comment reads as if avoiding dangling references would solve the issue with the broken sorting but it does not. Perhaps I am just overinterpreting, though that is what I refer to.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.