станд :: набор> :: find (), без конструкции копирования строки - PullRequest
3 голосов
/ 10 января 2011

У меня есть std :: набор std :: пар, а вторая пара - строка. Я хочу проверить, существует ли пара в наборе.

std::set< std::pair<size_t, std::string> > set_;

bool exists(size_t x, const std::string& s)
{
    std::set< std::pair<size_t, std::string> >::iterator i = set_.find(std::make_pair(x, s)); // copy of s is constructed by make_pair!
    return i != set_.end();
}

Я вызываю эту функцию часто (да, очень часто), поэтому я хочу выполнить эту проверку, не делая временную копию строки. Есть ли способ сделать это, который так же прост и лаконичен, как у меня здесь, но который не делает временную копию строки? Было бы неплохо любое решение с контейнерами STL или Boost.

Ответы [ 5 ]

5 голосов
/ 10 января 2011

Использовать указатель на строку и меньше переопределять предикат (см. Конструктор std :: set)

2 голосов
/ 10 января 2011

Действительно ли профилирование показало, что копирование строки является существенной проблемой здесь?

Если да, можете ли вы изменить функцию существующие, чтобы она принимала pair вместо двух аргументов, и организоваластрока, которая будет построена непосредственно в паре, а не отдельно?

Если вы не можете этого сделать, вы всегда можете использовать shared_ptr<std::string> в качестве второго элемента вашего pair и придумать функцию сравнения, котораясравнивает строки из адресов, а не строк значений.

1 голос
/ 10 января 2011

К сожалению, вы не можете сделать это в стандартной библиотеке C ++, не изменив key_type на что-то похожее на ссылку.Существуют другие библиотеки контейнеров, которые имеют параметризованную функцией поиска функцию поиска, которая допускает различные типы поиска и компараторы (например, Boost.Intrusive).Кроме этого, вы можете просто надеяться, что оптимизатор удалит конструкцию копирования.(Benchmark!)

1 голос
/ 10 января 2011

Вы всегда можете найти себя.

static pair<size_t, std::string> helper(0,"");
typedef std::set< std::pair<size_t, std::string> >::iterator iterator_type;
helper.first = x;
for (iterator_type i = set_.lower_bound(helper); i != set_.end(); ++i) {
    if (i->first != x)
        return false;
    if (i->second == s)
        return true;
}
return false;
0 голосов
/ 10 января 2011

Напишите функтор, который хранит ссылку на целевую строку:

struct match_str : public std::unary_function<bool, std::string>
{
  match_str(const std::string& s) : s_(s) {};
  bool operator()(const std::pair<size_t, std::string>& rhs) const
  {
    return rhs.second == s_;
  }
};

Использование:

std::set< std::pair<size_t, std::string> >::iterator i = std::find_if( set_.begin(), set_.end(), match_str(s) );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...