静态智能指针 - Yay还是Nay?

时间:2014-06-07 06:33:57

标签: c++ c++11

假设我有一个对象 - 我们将它称为Obj--我希望它包含一个指向它自己类型的实例的静态指针。例如:

class Obj{
    static auto get_active_obj() -> const Obj*;
    auto make_active_obj() -> void;

private:
    static const Obj* active;
};

现在,在这种情况下使用智能指针,特别是shared_ptr是不错的做法?这里使用shared_ptr的想法是,当用户使用get_active_obj查询对象时,我只能将weak_ptr返回给活动对象,用户可以查询它以检查活动对象是否已更改/仍然有效。现在,问题是,这是最优化(甚至可行)的解决方案吗?例如:

class Obj{
    static auto get_active_obj() -> std::weak_ptr<const Obj>;
    auto make_active_obj() -> void;

private:
    //another concern with this is that I have to provide a "no-OP" 
    //deleter to prevent a segfault when the shared_ptr tries to delete a static    
    //pointer.
    static std::shared_ptr<const Obj> active;
};

int main(){
    Obj o;
    o.make_active_obj();

    auto active = Obj::get_active_obj();
    if(active.expired()){ //is it still active?
        auto active_obj = active.lock();
        //do stuff
    }

}

make_active_obj()的概念实现:

auto make_active_obj()const -> void {
    active.reset(this);
}

~Obj(){
    if(this == active.get())
        active.reset();
}

2 个答案:

答案 0 :(得分:4)

我会在你的程序中反转使用shared和weak_ptr。那就是:我会使用静态weak_ptr来保存对当前活动对象的引用,但只要有人调用shared_ptr以便使用它就会返回get_active_obj()

class Obj{
    static std::shared_ptr get_active_obj();
    void make_active_obj();

private:
    static std::weak_ptr<const Obj> active;
};

int main(){
    Obj o;
    o.make_active_obj();

    auto active = Obj::get_active_obj();
    if(active){ //is it still active?
        //do stuff
    }
}

原因是您可能希望能够销毁/关闭活动对象,而无需在此之前激活其他对象(例如,在终止程序之前)。
这也更适合程序的语义:当某个函数想要使用活动对象时,必须确保在处理对象时不会销毁该对象,因此这是一个(临时)拥有关系。另一方面,类可能并不关心对象是否被销毁,因为它只提供对程序其他部分的引用,因此这是一种非拥有关系。

答案 1 :(得分:1)

在某些代码调用get_active_obj()后应该删除活动对象吗?由于您的对象似乎在堆栈中,答案显然是否定的。因此,get_active_obj()应该绝对不返回拥有指针。我会这样做:

class Obj{
    static const Obj* get_active_obj() {return active;}
    void make_active_obj() const {active = this;}

    ~Obj() {if (active==this) active=nullptr;}    
private:
    static const Obj* active;
};

由于get_active_obj()的收件人不拥有Obj,他们所需要的只是一个指针。 (它将是一个引用,但你不能有一个可空引用,所以它是指针。另请注意,当调用Obj的析构函数时,它使自己不再是活动指针。简单。

当然,这个答案是100%基于你的Obj在堆栈上或以其他方式管理的事实。如果您希望make_active_obj分享所有权,请参阅其他答案。