почему std :: equal_to вызывает динамическое распределение?
Рассмотрим следующий простой пример, где я использую std::equal_to
для сравнения двух std::pair<std::string, unsigned>
. operator new
перегружен так, что она печатает сообщение, когда распределение имеет место (живой код здесь):
#include <functional>
#include <string>
#include <iostream>
// overloaded to see when heap allocations take place
void* operator new(std::size_t n)
{
std::cout << "Allocating " << n << std::endl;
return malloc(n);
}
int main()
{
using key_type = std::pair<std::string, unsigned>;
auto key1 = std::make_pair(std::string("a_______long______string______"), 1);
auto key2 = std::make_pair(std::string("a_______long______string______"), 1);
std::cout << "Finished initial allocations\n\n" << std::endl;
std::equal_to<key_type> eq;
eq(key1, key2); // how can this cause dynamic allocation???
}
Сообщение, которое я вижу, это
Allocating 31
Allocating 31
Finished initial allocations
Allocating 31
Allocating 31
Вы можете увидеть, что при сравнении key1
и key2
происходит два распределения. Но почему? Оператор std::equal_to
принимает свои аргументы по ссылке const, поэтому распределение не должно происходить... чего я не вижу? Благодарю.
Ответы
Ответ 1
Это потому, что вы делаете копии пар.
Типы keyX
- std::pair<std::string, int>
. eq
имеет оператор вызова функции для аргументов const std::pair<std::string, unsigned>&, const std::pair<std::string, unsigned>&
. Поскольку типы не совпадают, ссылки не могут напрямую привязываться к аргументам. Однако int
неявно конвертируется в unsigned
и поэтому данная пара неявно конвертируется в пару аргументов.
Таким образом, вы неявно создаете пару временных аргументов для сравнения. Создание временных строк вызывает выделение памяти.
Если бы вы использовали std::equal_to<>
в качестве оператора сравнения, он бы не создавал копии, поскольку выводил типы аргументов и, следовательно, не вызывал преобразование.