Подтвердить что ты не робот

Компараторы в std:: priority_queue

Есть ли причина, по которой конструктор std::priority_queue принимает компаратор по постоянной ссылке? Что делать, если компаратор выходит из области видимости?

Я думал об этом в контексте возможного перемещения компаратора, как указал @LightnessRacesInOrbit!

Прошу прощения, если об этом уже было сообщено. Я не смог его найти!

4b9b3361

Ответ 1

Я никогда не думал об этом раньше, а 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).

Lambdas не могут быть назначены для копирования, но они являются копируемыми, поэтому здесь нет проблем.

[C++14: 5.1.2/20]: Тип замыкания, связанный с lambda-выражением, имеет удаленный (8.4.3) конструктор по умолчанию и оператор удаления удаленной копии. Он имеет неявно объявленный конструктор копирования (12.8) и может иметь неявно объявленный конструктор перемещения (12.8). [..]

Предотвращает ли это перемещение-компоновку самого компаратора? Да. Я собираюсь предположить, что это соглашение, взяв компаратор const-ref, затем скопировав его, проистекает из STL-дней, до семантики перемещения. Я полагаю, что серьезно не рассматривалось добавление перегрузок, чтобы использовать компаратор по значению, потому что это добавляет сложности, и в первую очередь вы не должны иметь сложный, способствующий движению компаратор (дайте им состояние, конечно, но не слишком), Тем не менее, это может стоить подняться с комитетом, если вы можете придумать твердый прецедент для перемещения компаратора.

Ответ 2

Это не выходит за рамки - это копия, сконструированная в контейнер. В описании cppreference.com указано:

explicit priority_queue( const Compare& compare = Compare(),
                         const Container& cont = Container() );

Копировать - создает базовый контейнер c с содержимым cont. Копирует-конструирует сравнительный функтор comp с содержимым сравнения. Вызывает std:: make_heap (c.begin(), c.end(), comp). Это также конструктор по умолчанию.

Существуют различные другие формы конструктора, но во всех случаях внутренний компаратор либо копируется, либо перемещается из того, который был поставлен.

Ответ 3

Конструктор

std::priority_queue делает копию предоставленного компаратора, поэтому это не проблема, если она выходит за рамки.

Вы можете использовать лямбда в качестве компаратора либо с помощью 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; });
}