I was shocked by the number of comments that did not show a basic understanding of object-oriented design (does this prove that C ++ is not an OO language?). Yes, the std :: pair design has some historical features, but it does not make a bad design good; and it should not be used as an excuse to deny this fact. Before I pounced on him, let me answer some of the questions in the comments:
Don't you think that int should also have a setter and getter
Yes, from a design point of view, we should use accessories because we don’t lose anything, but we get additional flexibility. Some new algorithms may want to pack extra bits into a key / value, and you cannot encode / decode them without accessories.
Why wrap something in a getter if there is no logic in the getter?
How do you know that there will be no logic in the getter / setter? Good design should not limit the possibility of implementation based on the assumption. It should offer as much flexibility as possible. Remember that the std: pair design also solves the iterator design, and by inviting users to directly access member variables, the iterator should return structures that actually store the key / values together. This turns out to be a big limitation. There are algorithms that must contain them separately. There are algorithms that do not explicitly store the key / values. Now they should copy the data during the iteration.
Contrary to popular belief, having objects that do nothing but store member variables using getters and setters is not a “way to do it”
Another wild guess.
OK, I would stay here.
To answer the original question: std :: pair decided to set up member variables because the one who designed it did not recognize and / or set the priority of the importance of the flexible contract. Obviously, they had a very narrow idea / vision of how key value pairs should be implemented in a map / hash table, and to worsen them, they allowed such a narrow look at the implementation to spread from above to jeopardize the design. For example, what if I want to implement the replacement std: unordered_map, which stores the key and values in separate arrays based on an open addressing scheme with linear sensing? This can significantly improve cache performance for pairs with small keys and large values, since you do not need to take a long jump through the spaces occupied by the values to verify the keys. If std :: pair chose accessors, it would be trivial to write an STL style iterator. But now it is simply impossible to achieve this without causing additional data copying.
I noticed that they also instructed to use open hashing (i.e. a closed connection) to implement std :: unordered_map. This is not only strange from a design point of view (why do you want to limit how everything is implemented?), But also rather dumb from an implementation point of view. Chained hash tables using a linked list are arguably the slowest of all categories. Go to Google on the Internet, we can easily find that std: unordered_map is often the cover of a hash table test. It even tends to be slower than Java HashMap (I don’t know how they managed to lag in this case, since HashMap is also a hash table). The old excuse is that a chain hash table tends to improve when load_factor approaches 1, which is completely invalid because 1) there are many methods in the open address family to solve this problem - have you ever heard of hopping or hashing with with the help of a robin-hood, the latter has really been there for 30 bizarre years; 2) the chain hash table adds pointer overhead (good 8 bytes on 64-bit machines) for each record, so when we say that the load_factor of the unordered map is approaching 1, this is not 100% memory usage! We must take this into account and compare the performance of unordered_map with alternatives with the same memory usage. And it turns out that alternatives like Google Dense HashMap are 3-4 times faster than std :: unordered_map.
Why are they relevant? Because it is interesting that mandatory open hashing makes the std :: pair design less bad, now that we do not need the flexibility of an alternative storage structure. Moreover, the presence of std :: pair makes it almost impossible to adopt newer / better algorithms for writing a replacement replacement std :: unordered_map. Sometimes you wonder if they did it intentionally so that the poor design of std :: pair and the pedestrian implementation of std :: unordered_map can survive longer. Of course, I'm joking, so whoever writes, do not be offended. In fact, people using Java or Python (well, I allow Python to stretch) would like to thank you for feeling good about being "as fast as C ++."