如何告诉对象另一个对象的死亡?

时间:2016-01-27 20:46:39

标签: c++ design-patterns

在我的工作中,我遇到了一个错误,可以描述如下。 有两个类,A类和B类:

class A
{
public:
    void print(){}
};  

class B
{
    A* a;
public:
    void init(A* _a) {
        a = _a;
    }
    void PrintWithA()
    {
        a->print();
    }
};

A* a;
B* b;
b->init(a);

// some code .....
delete a;        // line 1
a = NULL;
// some code .....

b->PrintWithA(); // line 2

对象“b”对对象“a”的状态一无所知。在第1行中,“a”对象已被删除,但在第2行,我们继续使用它。当有很多代码时,很容易犯这样的错误。 我的问题是以下 - 用于避免一些错误的approch?我想我可以使用观察者模式 - 但我认为这是不合理的昂贵解决方案。 感谢的。

3 个答案:

答案 0 :(得分:0)

你应该使用弱ptr(http://en.cppreference.com/w/cpp/memory/weak_ptr

基本上你可以为B级提供一个弱的ptr A。

每当有时间访问A时,您可以尝试锁定弱ptr以查看它是否仍然有效。

#include <memory>

class A
{
public:
    void print(){}
};  

class B
{
    std::weak_ptr<A> a;
public:
    void init(std::weak_ptr<A> _a) {
        a = _a;
    }
    void PrintWithA()
    {
        if (auto spt = a.lock()) { 
            spt->print();
        }
    }
};

int main()
{
    std::shared_ptr<A> a = std::make_shared<A>();
    std::unique_ptr<B> b = std::make_unique<B>();
    b->init(a);

    // some code .....
    a = nullptr;
    // some code .....

    b->PrintWithA(); // line 2
    return 0;
}

答案 1 :(得分:0)

为了防范这种情况,要么B在构造对象B时需要拥有A的生命周期,要么需要计算A引用。

C ++ 11我认为有一个共享指针的概念来维护引用,并且如果有人有引用,它将阻止对象A被删除。见std::shared_ptr

如果您不使用C ++ 11,则boost::shared_ptr基本上会执行相同的操作。但是你需要我个人不喜欢使用的升级库,但它取决于你。

像这样使用它们:

typedef std::shared_ptr<A> A_ptr;

A_ptr a = new A();

class B
{
    A_ptr a;
public:
    void B(A_ptr _a) {
        a = _a;
    }
    void PrintWithA()
    {
        a->print();
    }
};

否则你可以自己把东西放在一起。有点像:

class A
{
public:
    A(){
      ref_count = 1;
    }

    void print(){}

    void grab() {
      ref_count++;
    }

    void release() {
      ref_count--;
      if (ref_count <= 0)
        ~A();
    }
private:
    int ref_count;

    ~A(){
      delete this;
    }
}; 

在B区内你分配指针并调用grab();

而不是打电话给删除(因为它是私人的而无法工作)你打电话 a-&gt;指针上的release()。

现在这并不是特别棒,因为你不能使用这种形式:

A a;

所以它并不理想。但是,如果您使用的某些编译器没有shared_ptr,并且您不介意限制,则可以使用此或其形式。通常,使用 shared_ptr

答案 2 :(得分:-2)

首先,说A* a;的行应该是A* a = new A;

在c ++中,您需要明确地对此感知进行编码,而不是自动完成。

您可以做的一件事是检查_aPrintWithA是否为NULL,但如果您确保在delete[]之后始终将指针设置为NULL,则无法执行此操作他们(你已经完成了)