Ответ 1
Основное отличие заключается в том, что они представляют собой разные несвязанные типы (с некоторыми неявными преобразованиями между ними).
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);
}
Пока существуют неявные преобразования, которые позволяют f(pc)
компилировать, эта строка включает преобразование, а преобразование включает в себя создание копии longstring()
s. С другой стороны, вызов f(cp)
связывает постоянную ссылку на существующую пару по типу, не требуя каких-либо копий.
Тот факт, что компилятор позволяет вам писать аналогичный код, не означает, что код скомпилирован, чтобы сделать то же самое. Это особенно справедливо для типов с неявными преобразованиями, как в случае std::pair
Это обычная ошибка при написании функторов для работы с элементами, хранящимися на картах, где несоответствие аргумента функтора приведет к ненужному копированию данных объекта:
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 << " ";
});
В приведенной выше лямбда не указан правильный аргумент (std::pair<int,std::string
vs. std::pair<const int,std::string>
), что заставляет каждый вызов копировать как индекс, так и значение (т.е. все строки будут скопированы до std::pair<int,std::string>
а затем ссылка на аргумент для лямбда). Простой рекомендацией в этом случае было бы использование std::map<int,std::string>::value_type const &
для типа аргумента.