Использование GNU Parallel выглядит так:
#!/bin/bash
echo_var(){
echo $1
return 0
}
export -f echo_var
seq -f "n%04g" 1 100 | parallel -P 10 echo_var {}
exit 0
Если вы используете версию 20170822, вам даже не нужно export -f
, пока вы это запустили:
. `which env_parallel.bash`
seq -f "n%04g" 1 100 | env_parallel -P 10 echo_var {}
Нет, это не будет.
vector<Instruction> ins;
хранит значения, а не ссылки. Это означает, что независимо от того, как вы, но этот объект Instruction там, он будет скопирован в какой-то момент в будущем.
Кроме того, поскольку вы выделяете new
, приведенный выше код течет, что объект. Если вы хотите сделать это правильно, вам нужно будет
vector<Instruction*> ins
Или еще лучше:
vector< std::reference_wrapper<Instruction> > ins
Мне нравится в этом блоге для объяснения reference_wrapper
Это поведение называется срезом объектов .
Итак, вам понадобится какой-то указатель. A std::shared_ptr
работает хорошо:
typedef shared_ptr<Instruction> PInstruction;
vector<PInstruction> v;
v.emplace_back(make_shared<Add>());
PInstruction i = v[0];
Имейте в виду, что PInstruction подсчитывается по ссылке, поэтому конструктор копирования PInstruction создаст новую «ссылку» на тот же объект.
Если вы хотите сделать копию ссылочного объекта, вам придется реализовать метод clone:
struct Instruction
{
virtual PInstruction clone() = 0;
...
}
struct Add
{
PInstruction clone() { return make_shared<Add>(*this); }
...
}
PInstruction x = ...;
PInstruction y = x->clone();
Если производительность является проблемой, чем вы можете посмотреть на std::unique_ptr
, это немного сложнее управлять, поскольку семантика перемещения всегда требуется, но она позволяет избежать затрат на некоторые атомные операции.
Вы также можете использовать необработанные указатели и управлять памятью вручную с помощью какой-либо архитектуры пула памяти.
Основная проблема заключается в том, что для получения полиморфного типа компилятор не знает, насколько велики будут подклассы, поэтому вы не можете просто иметь вектор базового типа, так как он не будет иметь дополнительное пространство, необходимое для подклассов. По этой причине вам нужно будет использовать семантику pass-by-reference, как описано выше. Это сохраняет указатель на объект в векторе, а затем сохраняет объект в куче в блоках разных размеров в зависимости от того, что требуется подклассу.
Нет, это не сработает; вы «нарезаете» объект Add
и вставляете только его Instruction
часть в массив. Я бы рекомендовал вам абстрагировать базовый класс (например, сделав execute
чисто виртуальным), так что нарезка дает ошибку компиляции, а не неожиданное поведение.
Чтобы получить полиморфное поведение, вектор должен содержать указатели на базовый класс.
Затем вам нужно быть осторожным, как вы управляете самими объектами, поскольку они больше не содержатся в векторе. Разумные указатели могут быть полезны для этого; и поскольку вы, вероятно, будете динамически распределять эти объекты, вы также должны дать базовому классу виртуальный деструктор, чтобы убедиться, что вы можете их правильно удалить.
Возможно, вы захотите сделать пару вещей: A: изменить тип «v» на «вектор», B: управлять вашей памятью с помощью оператора «delete». Чтобы ответить на ваш вопрос, при таком подходе, да, но вы сможете получить доступ к интерфейсу только из «Инструкции», если вы ЗНАЕТ тип чего-то, на который указывает указатель «Инструкция», я бы предложил использовать dynamic_cast, если вам нужно доступ к интерфейсу, скажем, «Добавить».