我有以下两个类:
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;
};
我假装第二个中的字段ref
是对另一个位置中的整数的引用,可能(但不是必需)某个类型为state
的实例的字段B
现在我想对这些类型执行一些操作,实际上,我使用了boost :: variant库。
using my_type = boost::variant<A, B>;
现在,当我处理my_type
变量时,所有工作都按预期工作。例如:
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"
}
但是当我使用std::vector
my_type
时,事情就出错了!
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
}
现在,我想知道这里发生了什么,即 在上面的代码中,if条件评估为false会发生什么?
有可能,我想就如何完成这项任务获得一些建议。 提前谢谢。
答案 0 :(得分:1)
问题是,当您向向量添加第二个元素时,它会重新分配更多内存并将第一个对象移动到新位置,并且您已经悬挂了引用。简单的解决方案是提前在std::vector
中保留足够的内存以防止重新分配或使用另一个不移动对象的容器。但是你的原始解决方案有一个设计缺陷 - 它依赖于它所引用的对象应该比它更长的事实。但是你的逻辑不能保证这会导致你在std::vector
中看到的问题。如果对象b
以某种方式超过对象a
,则第一个示例中可能出现相同的问题。更好的解决方案是使用智能指针,让B
类型的对象持有指向A
类型对象的共享或弱指针,取决于您想拥有的所有权。这样你就可以在std::vector
中拥有共享指针,内存重新分配不会对你产生影响:
struct A {
A() : state(0) { }
A(int state_arg)
: state{ state_arg } { }
int state;
};
typedef std::shared_ptr<A> APtr;
struct B {
B(int state_arg, const APtr& ptr)
: state{ state_arg }, aptr{ ptr } { }
int state;
APtr aptr;
int ref() const { return aptr->state; }
}
typedef std::shared_ptr<B> BPtr;
using my_type = boost::variant<APtr, BPtr>;