两个类之间的共享指针作为类成员

时间:2017-04-26 09:30:13

标签: c++ shared-ptr

我有以下类结构:

class Bar {
private:
    std::shared_ptr<std::vector<int>> y_;
public:
    Bar(std::shared_ptr<std::vector<int>> p):
        y_(p)
    {}

    int getFirstVal() {return y_->at(0);};
};

class Initialiser {
private:
    std::vector<int> x_;
    Bar bar_;
public:
    Initialiser(std::vector<int>& v):
        x_(v),
        bar_(std::make_shared<std::vector<int>>(x_))
    {}

    void set_x(std::vector<int> x) {x_ = x;}

    void check(std::vector<int> x){
        set_x(x);
        std::cout << "New value of x= " << bar_.getFirstVal() << std::endl;
    }
};



int main(){

    std::vector<int> z = {1,2,3};
    Initialiser init(z);

    std::vector<int> x_new = {4,5,6};
    init.check(x_new); // should print 4



}

在类Initialiser中,我将私有成员作为int的向量和类Bar的实例。应该使用指向int向量的共享指针初始化Bar,并且应该在Initialiser和Bar之间共享此向量。但是,目前,如果Initialiser调用x的setter,则不会影响bar内的向量。我在 check()中演示了这一点。为什么 check()不打印值4但仍然是值1?

1 个答案:

答案 0 :(得分:4)

Initialiser(std::vector<int>& v):
    x_(v),
    bar_(std::make_shared<std::vector<int>>(x_))
{}

您创建了一个shared_ptr,它指向一个新的向量,即x_的副本。当然,修改一个不会影响另一个。

直接的解决方案是让Initialiser和Bar将vector_ptr保存到向量:

class Initialiser {
private:
    std::shared_ptr<std::vector<int>>  x_;
    Bar bar_;
public:
    Initialiser(std::vector<int>& v):
        x_(std::make_shared<std::vector<int>>(v)),
        bar_(x_)
    {}
};

但是由于Bar对象是Initialiser对象的一部分,所以根本不需要智能指针。 Bar可以简单地保存对向量的引用。这里没有终身管理问题,因为bar_永远不会比它的容器寿命更长,容器也不会超过吧_。

class Bar {
private:
    std::vector<int>& y_;
public:
    Bar(std::vector<int>& p):
        y_(p)
    {}

    int getFirstVal() {return y_.at(0);};
};

class Initialiser {
private:
    std::vector<int>  x_;
    Bar bar_;
public:
    Initialiser(std::vector<int>& v):
        x_(v),
        bar_(x_)
    {}
};

但请注意,x_和bar_的顺序很重要,因此这有点脆弱。成员变量的构造顺序是它们在类定义中的出现顺序,而不是它们在成员初始化列表中的顺序。如果顺序颠倒了,程序的行为将是未定义的,因为bar_将在x _之前构造。

这种正确的排序还可以确保在对象销毁期间x_不会超过bar_,因为成员会以与初始化相反的顺序被销毁。