Компараторы в std:: очередь приоритетов
есть ли причина, по которой std::priority_queue
конструктор принимает компаратор по постоянной ссылке? Что делать, если компаратор выходит за рамки?
Я думал об этом в контексте возможного перемещения компаратора, как указал @LightnessRacesInOrbit!
Мне жаль, если об этом уже было сообщение. Я не смог его найти!
3 ответов
Я никогда не думал об этом раньше, и const-ref действительно немного вводит в заблуждение. Однако сигнатура функции была придумана до появления семантики перемещения, и стало модным принимать все по значению. Действительно, компаратор копируется!
[C++14: 23.6.4.1/4]:
эффекты: инициализируетcomp
Сx
иc
Сy
(копировать построение или перемещать построение по мере необходимости); вызовыc.insert(c.end(), first, last);
и, наконец, вызовыmake_heap(c.begin(), c.end(), comp).
лямбды не копируются, но они are копировать-конструктивный, поэтому здесь нет проблем.
[C++14: 5.1.2/20]:
тип закрытия, связанный с лямбда-выражение имеет удаленный (8.4.3) конструктор по умолчанию и оператор назначения удаленной копии. Он имеет неявно объявленный конструктор копирования (12.8) и может иметь неявно объявленный конструктор перемещения (12.8). [..]
предотвращает ли это перемещение-построение самого компаратора? Да, это так. Я собираюсь предположить, что это соглашение о том, чтобы взять компаратор const-ref, а затем скопировать его, происходит от дней STL, задолго до семантики перемещения. Я полагаю, что серьезно не рассматривалось добавление перегрузок, чтобы взять компаратор по значению, потому что это добавляет сложность, и у вас не должно быть сложного, улучшающего перемещение компаратора в первую очередь (дайте им состояние, конечно, но не слишком много). И все же это ... --12-->мая стоит поднять с комитетом, если вы можете придумать надежный вариант использования для перемещения компаратора.
Он не выходит за рамки-это копия, построенная в контейнер. Описание на cppreference.com состояния:
explicit priority_queue( const Compare& compare = Compare(),
const Container& cont = Container() );
Copy-создает базовый контейнер c с содержимым cont. Copy-создает функтор сравнения comp с содержимым compare. Вызовы std:: make_heap(c.begin (), c.end (), comp). Это также конструктор по умолчанию.
существуют различные другие формы конструктора, но во всех случаи внутренний компаратор или экземпляр-или двигает-построен от одного поставленного.
делает копию компаратора, поэтому это не проблема, если он выходит за рамки.
вы можете использовать лямбда-выражение в качестве компаратора с помощью std::function<bool(const T&, const T&)>
как тип компаратора, или сразу:
auto comp = [](int x, int y) { return x > y; };
std::priority_queue<int, std::vector<int>, decltype(comp)> q(comp);
вы можете облегчить это с помощью вспомогательной функции:
template<typename T, typename Compare>
auto make_priority_queue(Compare&& comp) {
return std::priority_queue<T, std::vector<T>, Compare>(std::forward<Compare>(comp));
}
int main() {
auto q = make_priority_queue<int>([](int x, int y) { return x > y; });
}