使用std :: vector,boost :: variant和带引用字段的类型

时间:2014-11-12 17:05:17

标签: c++ boost std stdvector boost-variant

我有以下两个类:

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会发生什么?

有可能,我想就如何完成这项任务获得一些建议。 提前谢谢。

1 个答案:

答案 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>;