3

我有一个 Visual Studio 2008 C++ 应用程序,我正在实现一个替换容器中使用的标准分配器,如std::vector. 但是,我遇到了一个问题。我的实现依赖于拥有资源句柄的分配器。在使用该功能的情况下rebind,我需要将句柄的所有权转移给新的分配器。像这样的东西:

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

不幸的是,我无法解除句柄所有权的旧分配器,因为它是const. 如果我const从重新绑定构造函数中删除,那么容器将不会接受它。

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

有没有解决这个问题的好方法?

4

4 回答 4

2

在没有真正了解分配器的情况下(从不需要它们):您的复制 ctor 需要一个constref,因此承诺不更改other对象,但无论如何您都尝试更改它。尽管在某些情况下类是这样设计的(std::auto_ptr),但这看起来确实很可疑。
从语法上讲,你总是可以声明h_ mutable,并创建Detach()一个const成员函数,但我会严重质疑这个设置的语义,然后再用一把阔剑闯入语法丛林。

于 2011-05-09T19:33:23.477 回答
1

如果您声明h_为会发生什么mutable

于 2011-05-09T18:58:41.563 回答
1

您可以通过额外的间接级别来解决这个问题,但这不是一个理想的解决方案。基本上,您的分配器将有一个指向句柄的指针,该句柄将在构造函数/析构函数中分配/释放。它指向的句柄自始至终都是非常量的,因此您可以将句柄从一个分配器“移动”到另一个分配器。不过,这确实给分配器增加了一些开销。

我不知道你的确切情况,但似乎应该仔细考虑一个非平凡可复制的有状态分配器的所有含义。是否有其他方法可以简化其设计,使其没有只能移动的手柄?

于 2011-05-12T13:01:58.780 回答
1

您不能转移所有权,因为即使在单个容器中,分配器也可能被复制和重新绑定多次,并且生成的实例同时使用。

您必须改为共享资源。使用引用计数为资源创建间接。就像是:

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; }
}

然后:

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

除了容器自然需要分配像hash_map/这样的异构块unordered_map外,众所周知,微软的容器实现会分配各种奇怪的东西。当我在一个 Windows 应用程序中跟踪分配时,有许多奇怪大小的分配来自 STL 内部的某个地方。

于 2011-05-12T13:32:32.523 回答