0

我很想了解 COW 的工作原理,我在 wikibooks 上找到了以下课程,但我不理解这段代码。

template <class T>
class CowPtr
{
    public:
        typedef boost::shared_ptr<T> RefPtr;

    private:
        RefPtr m_sp;

        void detach()
        {
            T* tmp = m_sp.get();
            if( !( tmp == 0 || m_sp.unique() ) ) {
                m_sp = RefPtr( new T( *tmp ) );
            }
        }

    public:
        CowPtr(T* t)
            :   m_sp(t)
        {}
        CowPtr(const RefPtr& refptr)
            :   m_sp(refptr)
        {}
        CowPtr(const CowPtr& cowptr)
            :   m_sp(cowptr.m_sp)
        {}
        CowPtr& operator=(const CowPtr& rhs)
        {
            m_sp = rhs.m_sp; // no need to check for self-assignment with boost::shared_ptr
            return *this;
        }
        const T& operator*() const
        {
            return *m_sp;
        }
        T& operator*()
        {
            detach();
            return *m_sp;
        }
        const T* operator->() const
        {
            return m_sp.operator->();
        }
        T* operator->()
        {
            detach();
            return m_sp.operator->();
        }
};

我会在共享的地图对象上的多线程应用程序中使用它。

map<unsigned int, LPOBJECT> map;

所以我已经将它分配给模板,现在我有:

CowPtr<map<unsigned int, LPOBJECT>> map;

现在我的问题:

  1. 我应该如何正确地为只想读取地图对象的随机线程获取地图实例?

  2. 例如,我应该如何从随机线程修改地图对象。插入新对象还是删除它?

4

2 回答 2

4

您发布的代码很差,以至于无法使用;作者似乎不明白constC++ 的工作原理。

实际上:CoW 需要对类上正在执行的操作有一些了解。当对被包装对象的操作可能修改时,CoW 包装器必须触发复制;在包装对象可以“泄漏”允许修改的指针或迭代器的情况下,它还必须能够记住这一点,一旦任何东西被泄漏,就需要进行深度复制。您发布的代码会根据指针是否为 const 来触发复制,这根本不是一回事。因此,使用 a时,即使指针不是 const,对 map的std::map调用也不应该触发写入时复制,并且即使指针是 const,调用也应该触发。std::map<>::findstd::map<>::insert

关于线程:如果不为每个可能发生变异的操作获取锁,就很难使 CoW 类线程安全,因为很难知道线程之间何时共享实际对象。如果对象允许指针或迭代器泄漏,那就更难了,标准库对象也是如此。

你没有解释为什么你想要一个线程安全的 CoW 映射。如果每次添加或删除元素时,地图的意义何在?如果只是用一些现有地图的副本启动单个实例,那么std::map有一个复制构造函数可以很好地完成这项工作,并且您不需要任何花哨的包装器。

于 2014-07-09T12:38:23.417 回答
1

这是如何运作的?

该类class CowPtr确实拥有一个指向底层对象的共享指针。它确实有一个私有方法来复制构造一个新对象并将指针分配给本地共享指针(如果任何其他对象确实持有对它的引用)void detach():.

此代码的相关部分是,它具有每个方法

const return_type&
method_name() const

一次没有 const。方法后的 const 保证方法不修改对象,该方法称为const 方法。由于对基础对象的引用也是 const ,因此每次您需要引用而不修改它时都会调用该方法。

但是,如果您选择修改引用后面的对象,例如:

CowPtr<std::map<unsigned int, LPOBJECT>> map;
map->clear();

T& operator->()正在调用非常量方法,该方法调用detach(). 通过这样做,如果有任何其他对象CowPtrshared_ptr正在引用相同的底层对象(<unsigned int, LPOBJECT>在这种情况下为的实例) ,则会生成一个副本

如何使用它?

只是如何使用 astd::shared_ptrboost::shared_ptr. 该实现的最酷之处在于它自动完成所有操作。

评论

但这不是COW,因为即使您不编写也会制作副本,如果您不保证不写 - 实现,它更像是副本

于 2014-07-09T12:37:38.023 回答