I have a simple class structure modelling a discrete simulation, with a vector of States, which each contain a number of Transitions, held as a vector of smart pointers. I've used smart pointers to hold the transitions as in my full application I need polymorphism.
#include <vector>
#include <memory>
class Transition {
public:
Transition() {}
};
class State {
public:
State(int num) : num(num), transitions() {}
void add_transition(std::unique_ptr<Transition> trans) {
transitions.push_back(std::move(trans));
}
private:
int num;
std::vector<std::unique_ptr<Transition>> transitions;
};
int main() {
std::vector<State> states;
for (int i = 0; i < 10; i++) {
State nstate = State(i);
for (int j = 0; j < 2; j++) {
nstate.add_transition(std::move(std::unique_ptr<Transition>(new Transition())));
}
// This line causes compiler errors
states.push_back(nstate);
}
}
I get compiler errors when adding the new state object to the vector:
Error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Transition; _Dp = std::default_delete<Transition>]’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
I imagine this is due to vector making a copy of the State object which is also trying to make a copy of the vector of unique_ptrs
which isn't allowed. I've seen that emplace_back
doesn't make copies like push_back
does but I still get the same error.
Adding the State object directly into the vector works, but I'd prefer to avoid this workaround as in my actual code I do more work with the State object rather than just adding transitions and don't want to keep accessing the vector.
int main() {
std::vector<State> states;
for (int i = 0; i < 10; i++) {
states.push_back(State(i));
for (int j = 0; j < 2; j++) {
states[i].add_transition(std::move(std::unique_ptr<Transition>(new Transition())));
}
}
}
State
is not copyable, but only moveable; But for states.push_back(nstate);
, nstate
is an lvalue (as a named variable), which can't be moved from. Then a copy is tried to perform but it's not allowed.
To solve it you could use std::move
(to turn it to an rvalue):
states.push_back(std::move(nstate));
LIVE
Note that after the move operation, the data member of nstate
(including the vector and its content) will be moved too.
// This line causes compiler errors states.push_back(nstate);
The nstate
object is an instance of the State
class. The State
class contains two data members: an int
(which is copyable), and a vector
of unique_ptr
s, that is movable but not copyable (since unique_ptr
is movable but not copyable). As a result of that, the whole State
class is movable but not copyable. So, you must std::move
the nstate
object into the states
vector:
states.push_back(std::move(nstate));
If you want copy semantics, you should use a vector of shared_ptr
s (that are reference counted smart pointers, and are both copyable and movable).
I would do also a few modifications to your State
class code:
class State { public: State(int num) : num(num), transitions() {}
Here, you should mark the constructor explicit
, to avoid implicit conversions from int
. Moreover, the std::vector
data member is automatically initialized, no need to use transitions()
here.
Moreover, considering this line of code:
states[i].add_transition(std::move(std::unique_ptr<Transition>(new Transition())));
you should to use std::make_unique
(introduced in C++14) instead of constructing a std::unique_ptr
with the raw pointer returned by an explicit call to new
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With