【问题标题】:VStudio 2012 Create custom allocator for container of move-only typeVStudio 2012 为只移动类型的容器创建自定义分配器
【发布时间】:2015-11-20 14:26:45
【问题描述】:

我正在尝试创建一个仅移动类型的 stl 容器,该容器在 VStudio 2012 中使用其自己的分配器。

问题是:似乎我必须为分配器提供构造函数,而分配器又需要访问包含类型的公共复制构造函数。

我要么得到:

错误 C2248:“std::unique_ptr<_ty>::unique_ptr”:无法访问在类“std::unique_ptr<_ty>”中声明的私有成员

错误 C2039: 'construct' : is not a member of 'MyAllocator'

相同的代码在 clang 中有效,所以我怀疑问题是由 Microsoft 引起的,但有人可以提出可能的解决方法吗?

这是我的最小复制代码

#include <memory>
#include <vector>

using namespace std;

template< typename T>
struct MyAllocator
{
typedef T value_type;
typedef value_type*         pointer;
typedef value_type&         reference;
typedef const value_type*   const_pointer;
typedef const value_type&   const_reference;
typedef size_t              size_type;
typedef ptrdiff_t           difference_type;


template<class t_other>
struct rebind
{
    typedef MyAllocator<t_other> other;
};

MyAllocator():m_id(0) {}
MyAllocator(int id):m_id(id){}

template <class T> 
MyAllocator(const MyAllocator<T>& other)
    :m_id(other.getId())
{

}  

T* allocate(std::size_t n)
{
    return reinterpret_cast<T*>(malloc(sizeof(T) * n));
}

void deallocate(T* p, std::size_t n)
{
    free(p);
}

int getId() const{ return m_id;}


//Have to add these although should not be necessary
void construct(pointer mem, const_reference value)
{
    std::_Construct(mem, value);      
}

void destroy(pointer mem)
{
    std::_Destroy(mem);
}

private:
    int m_id;
};

template <class T1, class U>
bool operator==(const MyAllocator<T1>& lhs, const MyAllocator<U>& rhs)
{
    return lhs.getId() == rhs.getId() ;
}

template <class T1, class U>
bool operator!=(const MyAllocator<T1>&, const MyAllocator<U>&)
{
    return lhs.getId()  != rhs.getId();
}

//define a move only type
typedef unique_ptr<uint32_t> MyIntPtr;

//define a container based on MyIntPtr and MyAllocator
typedef vector<MyIntPtr, MyAllocator<MyIntPtr> > MyVector;

int main(int argc, char* argv[])
{
   MyAllocator<MyIntPtr> alloc1(1);

   MyVector vec(alloc1);

   uint32_t* rawPtr = new uint32_t;
   *rawPtr = 18;

   vec.emplace_back(rawPtr);
   return 0;
}

【问题讨论】:

  • 你用哪个clang版本编译这个? gcc.godbolt.org 似乎显示了不同的结果 - 用 clang 编译也失败了。
  • constructT&amp;&amp; 作为第二个参数,并从它移开。更一般地说,在 C++11 下,construct 应该采用任意一组参数,并执行 new(p) T(std::forward(args)) 的等价物(不确定 VC12 是否足够好地支持 C++11 以允许这样做)。这是支持emplace 和类似内容所必需的。

标签: c++11 visual-studio-2012 stl allocator


【解决方案1】:

您得到的错误是因为您尝试从对相同类型的std::unique_ptr 的常量引用构造std::unique_ptr - 并且没有这样的构造函数。

你可以修改你的 construct 方法来获取一个右值引用,然后一切都编译得很好:

void construct(pointer mem, value_type&& value)
{
    std::_Construct(mem, std::move(value));      
}

【讨论】:

  • 不应该是std::_Construct(mem, std::move(value)); ?
  • 或模板 void构造(指针mem,T3&&值){std::_Construct(mem,std::forward(值));两者似乎都有效
  • 实际上,这里的 move vs forward 让我思考了一下 - 我编辑了 3 次答案:D 好吧,根据我的理解,forward 似乎更合适,因为您想在参考折叠后按原样转发值但我可能是错的,如果有人证明了 move 在这种情况下的优越性,我会很高兴地编辑:) 我对 C++11 的能力仍然不强,但根据我的理解,这里似乎更合适。跨度>
  • 我认为 std::forward 只有一个用例,那就是转发您使用模板获得的通用参考。 stackoverflow.com/questions/9671749/…
  • @DavidWoo 也许我错了,但由于值类型可以有不同的构造函数,在这种情况下不应该需要完美的转发吗?同样,不是 100% 确定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-05
  • 2014-02-08
  • 2020-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多