почему 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<> в качестве оператора сравнения, он бы не создавал копии, поскольку выводил типы аргументов и, следовательно, не вызывал преобразование.