Единственный пример кода, приведенный для указателей, и только более упомянутое IMO std::reference_wrapper
было упомянуто без указания того, как его можно использовать в подобной ситуации. Я хочу это исправить!
Не владеющие указатели имеют как минимум 3 недостатка:
- визуальное, от необходимости перчить
&
, *
и ->
в коде с их использованием;
- практический: если все, что вам нужно, это ссылка на один объект, теперь у вас есть вещь, которую можно вычесть из других указателей (которые могут быть не связаны), увеличить / уменьшить (если не
const
), сделайте вещи в разрешении перегрузки или преобразовании и т. д. & ndash; ничего из того, что вы хотите. Я уверен, что все смеются над этим и говорят: « Я бы никогда не совершил таких глупых ошибок », но вы знаете, что в течение достаточно долгого времени это будет случается.
- и отсутствие самодокументирования, поскольку они не имеют врожденной семантики владения или ее отсутствия.
Я обычно предпочитаю std::reference_wrapper
, что
- четко документирует свою чисто наблюдательную семантику,
- может дать только ссылку на объект, таким образом, не имея никаких ловушек, подобных указателю, и
- обходит многие синтаксические проблемы, неявно преобразуя их в реальный ссылочный тип, таким образом сводя к минимуму шум оператора, когда вы можете вызвать преобразование (передать функцию, инициализировать ссылку, range-
for
и т. Д.) ... хотя и мешать современное предпочтение auto
- по крайней мере, пока мы не получим предложенный operator.
или operator auto
& ndash; и требует более подробного .get()
в других случаях или если вы просто хотите избежать таких несоответствий. Тем не менее, я утверждаю, что эти морщины не хуже, чем у указателей, и, вероятно, не будут постоянными, учитывая различные активные предложения по предварительному подтверждению использования типов оболочки / прокси.
Я бы порекомендовал тот или иной класс словарного запаса, особенно для открытых данных. Есть экспериментальное предложение (предложения) для observer_ptr
s и еще много чего, но, опять же, если вам не нужно поведение, похожее на указатель, то вам следует использовать оболочку, которая моделирует ссылку ... и у нас уже есть один из те.
Итак ... код в принятом ответе можно переписать примерно так (теперь с #include
с и моими предпочтениями форматирования):
#include <algorithm>
#include <functional>
#include <vector>
// ...
void
modify_top_n(std::vector<Foo>& v, int const n)
{
std::vector< std::reference_wrapper<Foo> > tmp{ v.begin(), v.end() };
std::nth_element( tmp.begin(), tmp.begin() + n, tmp.end(),
[](Foo const& f1, Foo const& f2){ return f1.score > f2.score; } );
std::for_each( tmp.begin(), tmp.begin() + n,
[](Foo& f){ f.winner = true; } );
}
При этом используется конструктор диапазона для построения диапазона reference_wrapper
с из диапазона действительных Foo
с и неявного преобразования в Foo&
в списках аргументов лямбда-выражения, чтобы избежать необходимости делать reference_wrapper.get()
(и тогда у нас гораздо менее беспорядочный прямой доступ к элементу .
вместо ->
).
Конечно, это можно обобщить: основным кандидатом на выделение вспомогательной функции многократного использования является построение vector< reference_wrapper<Foo> >
для произвольного Foo
, учитывая только пару итераторов - Foo
. Но мы всегда должны оставлять что-то в качестве упражнения для читателя. : P