我有一个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'
有没有解决这个问题的好方法?
没有真正了解分配器(从不需要它们):你的复制 ctor 需要一个const
引用,从而承诺不更改other
对象,但你还是尝试更改它。虽然有些情况下类是这样设计的(std::auto_ptr
),但这确实看起来很可疑。
在语法上,你总是可以声明h_
mutable
,并Detach()
成为const
成员函数,但我会认真质疑这个设置的语义,然后再使用阔剑在句法丛林中破解。
如果你h_
声明为mutable
会怎样?
您可以使用额外的间接级别来解决此问题,但这不是理想的解决方案。基本上,您的分配器将有一个指向句柄的指针,该句柄将在构造函数/析构函数中分配/解除分配。它指向的句柄自始至终都是非常量,因此您可以将句柄从一个分配器"移动"到另一个分配器。不过,这确实会增加分配器的一些开销。
我不知道您的确切情况,但似乎应该仔细考虑一个非平凡可复制的有状态分配器的所有含义。有没有另一种方法可以简化其设计,使其没有仅移动手柄?
您无法转让所有权,因为即使在单个容器中,分配器也可能被多次复制和重新绑定,并且同时使用生成的实例。
您必须改为共享资源。为具有引用计数的资源创建间接寻址。像这样:
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
)之外,众所周知,容器Microsoft实现会分配各种奇怪的东西。当我在一个 Windows 应用程序中跟踪分配时,有许多来自 STL 内部某个奇怪大小的分配。