简体   繁体   English

复制就写正确用法?

[英]Copy on write proper usage?

I'm tyring to understand how COW works, I found following class on wikibooks, but I don't understand this code. 我想了解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->();
        }
};

And I would use it in my multithreaded application on map object, which is shared. 我将在共享的map对象的多线程应用程序中使用它。

map<unsigned int, LPOBJECT> map;

So I've assigned it to template and now I have : 所以我已经将其分配给模板,现在我有:

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

And now my questions : 现在我的问题是:

  1. How I should propertly take instance of the map for random thread which want only read map objects ? 我应该如何只为只读取映射对象的随机线程获取映射实例?

  2. How I should modify map object from random thread, for ex. 我应该如何从随机线程修改地图对象,例如。 insert new object or erase it ? 插入新对象还是删除它?

The code you post is poor to the point of being unusable; 您发布的代码很糟糕,无法使用。 the author doesn't seem to understand how const works in C++. 作者似乎并不了解const在C ++中的工作方式。

Practically speaking: CoW requires some knowledge of the operations being done on the class. 实际上:CoW需要一些有关在课堂上进行的操作的知识。 The CoW wrapper has to trigger the copy when an operation on the wrapped object might modify; 当对包装对象的操作可能进行修改时,CoW包装器必须触发复制。 in cases where the wrapped object can "leak" pointers or iterators which allow modification, it also has to be able to memorize this, to require deep copy once anything has been leaked. 如果包装的对象可以“泄漏”允许修改的指针或迭代器,则它还必须能够记住这一点,以便在任何内容泄漏后进行深度复制。 The code you posted triggers the copy depending on whether the pointer is const or not, which isn't at all the same thing. 您发布的代码将根据指针是否为const触发复制,这完全不是同一回事。 Thus, with an std::map , calling std::map<>::find on the map should not trigger copy on write, even if the pointer is not const, and calling std::map<>::insert should, even if the pointer is const. 因此,使用std::map ,即使指针不是const,在地图上调用std::map<>::find 也不应触发写入时的复制,而调用std::map<>::insert应该可以,即使指针是const。

With regards to threading: it is very difficult to make a CoW class thread safe without grabbing a lock for every operation which may mutate, because it's very difficult to know when the actual objects are shared between threads. 关于线程:要确保CoW类线程的安全而不对可能会发生变化的每个操作都抓住锁是非常困难的,因为很难知道线程之间何时共享实际对象。 And it's even more difficult if the object allows pointers or iterators to leak, as do the standard library objects. 如果对象允许指针或迭代器泄漏,则更困难,就像标准库对象一样。

You don't explain why you want a thread-safe CoW map. 您无需解释为什么要线程安全的CoW映射。 What's the point of the map if each time you add or remove an element, you end up with a new copy, which isn't visible in other instances? 如果每次添加或删除元素都会得到一个新的副本,而在其他实例中不可见,那么地图的意义是什么? If it's just to start individual instances with a copy of some existing map, std::map has a copy constructor which does the job just fine, and you don't need any fancy wrapper. 如果只是用一些现有地图的副本开始单个实例,则std::map有一个复制构造函数可以很好地完成工作,并且您不需要任何精美的包装器。

How does this work? 这是如何运作的?

The class class CowPtr does hold a shared pointer to the underlying object. class CowPtr确实拥有指向基础对象的共享指针。 It does have a private method to copy construct a new object and assign the pointer to to the local shared pointer (if any other object does hold a reference to it): void detach() . 它确实有一个私有方法来复制构造一个新对象并将该指针分配给本地共享指针(如果任何其他对象的确持有对该对象的引用): void detach()

The relevant part of this code is, that it has each method as 这段代码的相关部分是,每个方法都有

const return_type&
method_name() const

and once without const. 而且一次没有const。 The const after a method guarantees that the method does not modify the object, the method is called a const method . 方法后的const保证该方法不会修改对象,该方法称为const方法 As the reference to the underlying object is const too, that method is being called every time you require a reference without modifying it. 由于对基础对象的引用也是const,因此每次您需要引用而不修改它时都会调用该方法。

If however you chose to modify the Object behind the reference, for example: 但是,如果您选择修改引用后面的对象,例如:

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

the non-const method T& operator->() is being called, which calls detach() . 正在调用非常量方法T& operator->() ,该方法将调用detach() By doing so, a copy is made if any other CowPtr or shared_ptr is referencing the same underlying object (the instance of <unsigned int, LPOBJECT> in this case) 这样,如果任何其他CowPtrshared_ptr引用相同的基础对象(在这种情况下, <unsigned int, LPOBJECT>的实例) <unsigned int, LPOBJECT>

How to use it? 如何使用它?

Just how you would use a std::shared_ptr or boost::shared_ptr . 以及如何使用std::shared_ptrboost::shared_ptr The cool thing about that implementation is that it does everything automatically. 该实现的有趣之处在于它会自动执行所有操作。

Remarks 备注

This is no COW though, as a copy is made even if you do not write, it is more a Copy if you do not guarantee that you do not write -Implementation. 但是,这不是COW,因为即使您不编写副本也会被复制,如果您不保证不编写 -Implementation,则它更是一个副本

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM