пользовательский распределитель, использующий перемещение для вектора потока
-
25-09-2019 - |
Вопрос
В настоящее время я изучаю параллелизм в C ++ и наткнулся на использование вектора потоков, который, как я полагаю, будет возможен в C ++ 0x.Однако мой текущий компилятор, похоже, не имеет реализации контейнеров с поддержкой перемещения, и поэтому я получаю ошибки, генерируемые из-за std::thread::thread(const std::thread&)
удален, т. е. я могу использовать конструктор перемещения / назначение перемещения только с std::thread
.
Прав ли я, думая, что мог бы обойти эту проблему, написав пользовательский распределитель, используя
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
вместо того , чтобы
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
?Или какая-то другая вариация на эту тему (возможно, с использованием перегрузки MyAllocator::construct).
Примечание:В основном это кратковременное учебное упражнение и достаточно эффективная работа, позволяющая поиграться с потоками в контейнерах.Я бы только использовал MyAllocator
в этом контексте.Однако, пожалуйста, также укажите мне на любые библиотеки, в которых это может быть реализовано, чтобы я мог покопаться в исходном коде.
Решение
Если ваш компилятор не предоставляет информацию о перемещении std::vector
тогда вам придется написать свою собственную специализацию по std::vector<std::thread>
вместо того, чтобы просто предоставлять пользовательский распределитель.Весь C ++03 vector
интерфейс основан на копировании: push_back()
копирует элементы в; resize()
инициализирует пустые элементы с помощью Копировать элемента, переданного в качестве второго параметра (даже если это значение по умолчанию T()
); resize()
, reserve()
, insert()
, erase()
и push_back()
будет Копировать элементы, если вектор нуждается в перераспределении, или элементы, которые в противном случае нуждаются в перемещении, и так далее.
Это настолько распространенная проблема, что я включил такую специализацию в свой (коммерческий) просто::поток реализация std::thread
.
Другие советы
Самый простой способ обойти эту проблему, чтобы выделить нити на кучу и манипулировать на них указателями.
Проверить Boost Pointer Container
библиотека: boost::ptr_vector<std::thread>
Мне кажется, что вы ищете.
Требование того, что контейнеры STD принимают только для копироваемых объектов, больше связаны с интерфейсами контейнеров C ++ 03, чем он делает с реализацией аллекатора. Например
vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);
Стандарт уверяет нас A == B верно. Однако, если T не были скопированы, то в лучшем случае A = B не скомпилируется, в худшем случае a = b непределен. Более того,
a.push_back(T());
Может привести к выделению нового пространства, а под капотом есть копии, сделанные для нового базового хранения от старого.
Кроме того, в стандарте C ++ 03 нет ничего, что говорит, что реализация фактически должна позвонить AlloCator.construct, и фактически много (например, GCC).
Стандарт C ++ 0x добавляет новые функции участника в интерфейс контейнера для подвижных типов и уточняет, как такие вещи, как оператор = ведут себя в их присутствии.
Смотрите www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf.