Существующие ответы решают простой запрошенный случай, в котором мы заранее знаем количество симуляций.Решение состоит в том, чтобы просто зарезервировать достаточно места в векторе имитации, чтобы такое перераспределение никогда не происходило.
Но что, если число симуляций не было известно, или имитации должны быть добавлены ad-hoc?
Одним из ответов может быть сохранение симуляции в std::list
, а не std::vector
.Однако затем мы теряем возможность случайного доступа к симуляциям.
Мы могли бы решить эту проблему, внедрив симуляцию в терминах идиомы дескриптор / тело.Дескриптор является подвижным и управляет временем жизни фактической реализации.
Пример Am (в котором я также дал концепцию запущенного моделирования своего собственного класса):
#include <memory>
#include <thread>
#include <vector>
struct SimulationParams {};
struct Simulation
{
// noncopyable
Simulation(Simulation const&) = delete;
Simulation& operator=(Simulation const&) = delete;
Simulation(SimulationParams params);
void run()
{
// complicated stuff
}
void saveToFile(std::string const& path);
};
class SimulationHandle
{
using impl_class = Simulation;
using impl_type = std::unique_ptr<impl_class>;
impl_type impl_;
public:
SimulationHandle(SimulationParams params)
: impl_(std::make_unique<impl_class>(std::move(params)))
{}
auto saveToFile(std::string const& path) -> decltype(auto)
{
return implementation().saveToFile(path);
}
auto runInThread() -> std::thread
{
return std::thread {
[&sim = this->implementation()]
{
sim.run();
}
};
}
auto implementation() -> impl_class&
{
return *impl_;
}
};
struct RunningSimulation
{
RunningSimulation(SimulationParams params)
: simHandle_{ std::move(params) }
, thread_ { simHandle_.runInThread() }
{
}
void join()
{
if (thread_.joinable())
thread_.join();
}
void saveToFile(std::string const& path)
{
join();
simHandle_.saveToFile(path);
}
private:
// DEPENDENCY: ORDER
// During constructor, thread_ depends on simHandle_ being constructed
SimulationHandle simHandle_;
std::thread thread_;
};
extern int nSimulations;
int main(){
using std::vector;
vector<RunningSimulation> simulations;
for (int i=0; i<nSimulations; i++)
simulations.emplace_back(SimulationParams());
for(auto&& rs : simulations)
rs.saveToFile("test.dat");
return 0;
}
ДалееУсовершенствования:
Текущий дескриптор реализован в терминах unique_ptr
- это означает, что только один дескриптор может иметь симуляцию.Возможно, мы захотим проиндексировать симуляцию несколькими способами, для чего потребуется более одного дескриптора.
Одним из возможных решений этого было бы просто заменить unique_ptr
на shared_ptr
для совместного владения.Еще может быть концепция дескриптора управления временем жизни (реализовано с shared_ptr
) и мониторами времени жизни (реализовано с weak_ptr
).