开发者

transferring object ownership on std::allocator rebind

I have a Visual Studio 2008 C++ application where I am implementing a replacement for the standard allocator used in containers like开发者_StackOverflow社区 std::vector. But, I've run in to an issue. My implementation relies on the allocator owning a handle to a resource. In the case where the rebind feature is used, I would need to transfer ownership of the handle to the new allocator. Something like this:

template< class T >
class MyAllocator
{
public:
    template< class U >
    explicit MyAllocator( const MyAllocator< U >& other ) throw() 
        :  h_( other.Detach() ) // can't do this to a `const`
    {
    };

    // ...

private:
    HANDLE Detach()
    {
        HANDLE h = h_;
        h_ = NULL;
        return h;
    };

    HANDLE h_;
}; // class MyAllocator

Unfortunately, I can't relieve the old allocator of the handle ownership because it is const. If I remove const from the rebind constructor, then the containers won't accept it.

error C2558: class 'MyAllocator<T>' : no copy constructor available or copy constructor is declared 'explicit'

Is there a good way around this issue?


Without really knowing much about allocators (never needed them): Your copy ctor takes a const ref, thus promising to not to change the other object, but you attempt to change it anyway. Although there's cases where classes were designed that way (std::auto_ptr), this does seem fishy.
Syntactically, you could always declare h_ mutable, and make Detach() a const member function, but I'd seriously question the semantics of this setup, before hacking my way through the syntactic jungle using a broadsword.


What happens if you declare h_ as mutable?


You can solve this with an extra level of indirection but it's not an ideal solution. Basically, your allocator would have a pointer to a handle which would be allocated/deallocated in the constructor/destructor. The handle that it points to would be non-const throughout, so you can "move" the handle from one allocator to another. This does add some overhead to the allocator though.

I don't know your exact case but it seems that a stateful allocator that's non-trivially copyable should be carefully considered for all its implications. Is there an alternate way you can simplify its design so it doesn't have a move-only handle?


You can't transfer the ownership, because the allocator may be copied and rebound multiple times even in a single container and the resulting instances used simultaneously.

You'll have to share the resource instead. Create an indirection for the resource with reference-count. Something like:

class SharedHandle {
    HANDLE h_;
    int count;
    SharedHandle(HANDLE h) : h_(h), count(1) {}
    ~SharedHandle() { CloseHandle(h_); } // or whatever to release the resource.
    SharedHandle *Ref() { ++count; return this; }
    void Unref() { if(!--count) delete this; }
}

and than:

explicit MyAllocator( const MyAllocator< U >& other ) throw() 
:  h_( other.h_->Ref() )

In addition to containers that naturally need to allocate heterogenous blocks like hash_map/unordered_map, Microsoft implementation of containers is known to allocate various strange things. When I traced allocations in one Windows application, there were many allocations of strange sizes comming from somewhere inside STL.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜