知道谁指向它的对象

时间:2012-06-07 01:35:32

标签: c++

我有3个不同的类(A,B,C),每个类都有一个共享对象(对象X)的shared_ptr。我想要做的是给对象X提供有关谁指向它的信息。例如,如果没有A对象指向它,则不需要计算A类在更新时仅使用的数据。对象X可以保存指向C对象的指针向量,这样它就可以在更新了与C对象相关的一些数据时调用它们上的函数(但是C对象仍然指向它来查询它的其他数据) )。

我想要做的是为每个类上的shared_ptr创建一个包装类,无论何时构造/赋值/销毁包装器,都会调用指向X上函数的指针(所有相同的情况都会增加/减少引用计数)在X)。这是代码中的想法:

class A
{
public:
    A() : m_ptr(&X::IncrementACount, &X::DecrementACount) { }

    void SetX( const std::shared_ptr<X> &ptr ) { m_ptr = ptr; }
private:
    shared_ptr_wrapper0<X> m_ptr;
};

class B
{
public:
    B() : m_ptr(&X::IncrementBCount, &X::DecrementBCount) { }

    void SetX( const std::shared_ptr<X> &ptr ) { m_ptr = ptr; }
private:
    shared_ptr_wrapper0<X> m_ptr;
};

class C
{
public:
    C() : m_ptr(this, &X::StoreCPointer, &X::RemoveCPointer) { }

    void SetX( const std::shared_ptr<X> &ptr ) { m_ptr = ptr; }
private:
    shared_ptr_wrapper1<X, const C*> m_ptr;
};

A和B都有一个包装的智能指针,指定的递增/递减函数不带参数。当包装的智能指针被设置/清除/等时,这些函数将在它包含的X对象上被调用,并递增/递减A / B计数器。

C有一个带有一个参数的包装智能指针(类型为const C *)。当它被设置/清除/等时,它上面的函数将被C的构造函数(this指针)存储在其上的数据调用,并将从对象X上的向量中添加或删除它。

所以我的主要问题是这个好主意?有没有更好的方法来实现跟踪谁指向对象的想法?这种想法是否有一个特定的名称(我无法想象我是第一个尝试这样的东西,但我在寻找它时没有找到任何东西所以也许我只是不知道正确的名称寻找...)

谢谢。

3 个答案:

答案 0 :(得分:4)

更简单的方法是观察者模式,即发布/订阅者。见http://en.wikipedia.org/wiki/Observer_pattern。您的X对象是发布者,可以提供3种不同的接口。您的A,B和C对象是订阅者,他们注册以获得更改通知。每个Observer都负责在X的订阅列表中添加和删除自己。当X中的某些内容发生变化时,相应订阅列表中的每个人都会通过其界面通知。

答案 1 :(得分:0)

您的问题是真正指向A对象的唯一对象是智能指针。因此,即使您在复制智能指针时可以通知您的对象(搜索侵入式指针),也无法知道正在复制智能指针,这是您真正想要的知道。

你需要像pub / sub模型这样的东西。

以下是伪代码,给出了我们想要跟踪两种不同类型订户的想法。

class A
{
private:
    std::vector<B&> subscriberB;
    std::vector<C&> subscriberC;

public:
    void Subscribe(const B& subscriber) { subscriberB.push_back(subscriber); }
    void Subscribe(const C& subscriber) { subscriberC.push_back(subscriber); }

    // An example of a function where the subscribing objects are notified.
    void SomeFunction()
    {
        // for each subscriber in subscriberB
        subscriber.SomeFunction();

        // for each subscriber in subscriberC
        subscriber.SomeOtherFunction();
    }

};

以上存储引用,假设订阅者超过了他们订阅的对象。如果没有,你应该在向量中加入智能指针。 此外,您可能希望阻止相同的对象订阅两次,或提供取消订阅的方法。

如果你想'强制'将B或C类型的对象与A相关联,你可以使它们的构造函数像:

// B ctor
B::B(shared_ptr<A> aPtr)
{
    myPointerToA = aPtr;
    myPointerToA ->subscribe(*this);
}

更好的方法是使用一个创建B的工厂方法,然后将它挂钩到A:这可以避免在构造函数中解除引用this,这有点气味。

更典型的方法是拥有一种订阅者类型“InterfaceSubscribeToA”,任何想要订阅A的类都会实现。这完全取决于你想要实现的目标,我只是提到它,以防你碰巧过度复杂化你的特定问题!

答案 2 :(得分:0)

您可以使用侵入式列表。制作class Base,然后让ABC继承该类。此外,最好的技巧不是将CAB区分开来,而是以相同的方式对待所有观察者(如果添加D,则会采取特殊措施) ,与C s不同?)。 Base课程非常适合。

class Base
{
public:
    virtual void notifyXObjectChanged(/* data you want to pass*/) {}
    void setX(X* obj)
    {
        if(obj != object)
        {
            if(object)
                object->removeFromList(this);
            object = obj;
            if(object)
                object->addToList(this);
        }
    }

private:
    friend class X;
    X* object;
    Base* next;
    Base* previous;
};

而且,在X:

class X
{
    // ...
public:
    void addToList(Base* obj)
    {
        if(first == 0 && last == 0)
        {
            // The list is empty
            first = last = obj;
            obj->previous = obj->next = 0;
        }
        else
        {
            // Add the object at the end of the list
            last->next = obj;
            obj->previous = last;
            obj->next = 0;
            last = obj;
        }
    }

    void removeFromList
    {
        // Code for removing an element in a list
    }

    void notify()
    {
        // iterate on the list
    }

private:
    Base* first;
    Base* last;
    // ...
};

优点:

  • 非常小的内存开销
  • 非常快

希望这有帮助