复制写正确用法?

时间:2014-07-09 12:11:49

标签: c++ multithreading copy-on-write

我想了解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. 如何从随机线程修改地图对象,例如插入新对象还是删除它?

2 个答案:

答案 0 :(得分:4)

您发布的代码很差,无法使用;该 作者似乎并不了解const在C ++中是如何工作的。

实际上说:CoW需要一些知识 在课堂上进行的操作。 CoW包装必须 当对包装对象的操作可能时,触发副本 修改;如果被包裹的物体可以&#34;泄漏&#34;指针 或允许修改的迭代器,它也必须能够 记住这一点,一旦有任何东西需要深层复制 泄露。您发布的代码会触发副本,具体取决于 指针是否为常量,这是完全相同的 事情。因此,使用std::map,调用std::map<>::find 即使指针,地图也应 not 触发写入时的复制 不是const,即使是std::map<>::insert也应该调用 指针是常量。

关于线程:制作CoW非常困难 类线程安全,无需为每个操作获取锁 这可能会变异,因为很难知道什么时候 线程之间共享实际对象。它甚至是 如果对象允许指针或迭代器,则更难 泄漏,标准库对象也是如此。

您无法解释为什么需要线程安全的CoW地图。什么&#39; S 每次添加或删除元素时,地图的点, 你最终得到一个新的副本,在其他副本中看不到 实例?如果它只是用于启动单个实例 一些现有地图的副本std::map有一个复制构造函数 哪个工作做得很好,你不需要任何幻想 包装

答案 1 :(得分:1)

这是如何运作的?

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

此代码的相关部分是,每个方法都是

const return_type&
method_name() const

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

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

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

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

如何使用?

如何使用std::shared_ptrboost::shared_ptr。关于该实现的很酷的事情是它自动完成所有操作。

<强>说明

这不是COW,因为即使你不写,也会制作副本,如果你不保证你不写 - 实现,那就更像是复制。