Это нормальный способ получить случайный элемент из контейнера? - PullRequest
3 голосов
/ 02 декабря 2011

Недавно я решил опробовать новую случайную библиотеку c ++ 11, и одна вещь пришла мне на ум ... избавиться от [rand ()% nelemennts] при выборе случайного элемента из контейнера.Причина в том, что я хочу повторяющуюся генерацию, когда использование rand-инкапсуляции не существует, потому что

auto set_a=generateSet(nelements1); //generateSet calls rand
auto set_b=generateSet(nelements2); //so set_b is determined by the previous line :(

Итак, это то, что я придумал: (обратите внимание, что это не потокобезопасно, оно разработано так, чтобы быть безопасным в некотором смыслечто вызовы generateSet не влияют друг на друга (изменяя состояние внутреннего значения rand))

template<typename container_type,typename element_type >
class RandElemGetter
{

    const container_type& containter_ref;
    std::uniform_int_distribution<size_t> distribution;
    std::mt19937 engine;
public:
    RandElemGetter(container_type& container): containter_ref(container),distribution(0,container.size()-1)
    {

    }
    element_type get()
    {
        return containter_ref[distribution(engine)];
    }
};

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

{
vector<int> v{1,2,3,1701,1729};
vector<int> result;
RandElemGetter<vector<int>,int> reg_v(v);
for(size_t i=0;i<nelements;++i)
result.push_back(reg_v.get());
}

Так что это нормально?Я знаю, что это не потокобезопасно, это не главное.Мне интересно, есть ли лучший "ограниченный" способ получения случайного элемента из контейнера с произвольным доступом.Это может быть изменено, возможно, с помощью std :: advance, чтобы работать для всех.

Ответы [ 2 ]

2 голосов
/ 02 декабря 2011
RandElemGetter(container_type container):
   containter_ref(container),distribution(0,container.size()-1)

Принимает контейнер по значению, создает временную копию и сохраняет ссылку на эту копию. Ссылка недействительна после завершения конструктора.

Вам нужно либо сохранить копию, либо передать аргумент по ссылке. Во всяком случае, хорошая идея передавать сложные объекты по постоянной ссылке, чтобы избежать ненужного копирования.

1 голос
/ 02 декабря 2011
  • Я бы использовал <typename container_type, typename value_type = container_type::typename value_type>. Контейнеры STL имеют typedef для своих value_types, поэтому обычно нет необходимости повторяться.
  • Правильное решение действительно вернуть *std::advance(containter_ref.begin(), distribution(engine));
  • Я бы переименовал get() в operator() и предоставил бы result_type typedef, чтобы соответствовать модели STL AdaptableGenerator

Возможно, вы захотите получить пик SGI random_sample от исходного STL; Я считаю, что GNU все еще имеет это как расширение.

...