I have the following two classes:
struct A {
A() : state(0) { }
A(int state_arg)
: state{ state_arg } { }
int state;
};
struct B {
B(int state_arg, const int& ref)
: state{ state_arg }, ref{ ref } { }
int state;
const int& ref;
};
I pretend the field ref
in the second one to be a reference to an integer in another location, maybe (but not necessary) the field state
of some instance of type B
.
Now I want to performs some operations over those types, Indeed, I use the boost::variant library.
using my_type = boost::variant<A, B>;
Now when I work with variables of my_type
all works as expected. For example:
int main() {
my_type a(A(45));
my_type b(B(45, boost::get<A>(a).state));
A& at = boost::get<A>(a);
B& bt = boost::get<B>(b);
if (at.state == bt.ref) {
std::cout << "AS EXPECTED" << std::endl;
}
// that prints "AS EXPECTED"
}
But when I work with a std::vector
of my_type
the things go wrong !
int main() {
std::vector<my_type> vec;
vec.push_back(A(45));
vec.push_back(B(45, boost::get<A>(vec[0]).state));
A& at = boost::get<A>(vec[0]);
B& bt = boost::get<B>(vec[1]);
if (at.state == bt.ref) {
std::cout << "SHOULD I EXPECTED THIS ?" << std::endl;
}
// the code doesn't print
}
Now, I want to know what is going on here, i.e What is occurring that in the code above that the if condition evaluation gives false ?
And is possible, I would like to receive some advice in how to accomplish this tasks. Thanks in advance.
Problem is that when you add second element to the vector, it reallocates more memory and moves first object to the new location and you have dangled reference. Simple solution would be to reserve enough memory in
std::vector
in advance to prevent reallocation or use another container that does not move objects. But your original solution has a design flaw - it relies on the fact that object it has reference to should outlive it. But your logic cannot guarantee that so it leads to the issue you see in thestd::vector
. Same issue could be in the first example if objectb
would outlive objecta
somehow. Better solution would be to use smart pointers and let objects of typeB
hold a shared or weak pointer to object of typeA
, depends on ownership you want to have. This way you will have shared pointers instd::vector
and memory reallocation would not affect you: