In C++, what's the difference in behavior between std::pair<const T, const U>
and const std::pair<T, U>
?
std::pair is a class template that provides a way to store two heterogeneous objects as a single unit. A pair is a specific case of a std::tuple with two elements.
const int * And int const * are the same. const int * const And int const * const are the same. If you ever face confusion in reading such symbols, remember the Spiral rule: Start from the name of the variable and move clockwise to the next pointer or type.
Another way to initialize a pair is by using the make_pair() function. g2 = make_pair(1, 'a'); Another valid syntax to declare pair is: g2 = {1, 'a'};
int const* is pointer to constant integer This means that the variable being declared is a pointer, pointing to a constant integer. Effectively, this implies that the pointer is pointing to a value that shouldn't be changed.
The core difference is that they are different unrelated types (with some implicit conversions among them).
void f(std::pair<std::string,std::string> const &);
std::string longstring();
int main() {
std::pair<const std::string,const std::string> pc
= std::make_pair(longstring(),longstring());
f(pc);
const std::pair<std::string,std::string> cp
= std::make_pair(longstring(),longstring());
f(cp);
}
While there are implicit conversions that allow f(pc)
to compile, that line involves a conversion, and the conversion involves making a copy of the longstring()
s. On the other hand, the call f(cp)
only binds a constant reference to the existing pair as the type matches, not requiring any copies.
The fact that the compiler let's you write similar code, does not mean that the code is compiled to do the same thing. This is particularly true for types with implicit conversions, as is the case of std::pair
This is a common pitfall when writing functors to operate on elements stored in maps, where a mismatch on the argument of the functor will cause unnecessary copying of the object data:
std::map<int,std::string> m = create_map();
std::for_each(m.begin(),m.end(),
[](std::pair<int,std::string> const &r) {
std::cout << r.second << " ";
});
The lambda above does not have the correct type of argument (std::pair<int,std::string
vs. std::pair<const int,std::string>
) and that causes each call to copy both the index and the value (i.e. all strings will be copied, to an std::pair<int,std::string>
and then a reference bound for the argument to the lambda). The simple recommendation in this case would be to use std::map<int,std::string>::value_type const &
for the argument type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With