我试图了解如何正确编写AllocatorAware容器。
我的理解是propagate_on_container_move_assignment
typedef指示在移动容器本身时是否需要复制某种Allocator
类型。
因此,由于找不到任何示例,因此我自己的尝试将如下所示:
给定一个容器类型Container
,一个Allocator
类型allocator_type
,以及一个内部allocator_type
数据成员m_alloc
:
Container& operator = (Container&& other)
{
if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
{
m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
other.m_alloc
);
}
return *this;
}
这样对吗?
另外,这里的另一个困惑是嵌套的typedef
propagate_on_container_move/copy_assignment
专门在谈论赋值...但是构造函数呢? AllocatorAware
容器的move构造函数或copy构造函数是否还需要检查这些typedef?我认为这里的答案是肯定的……,这意味着,我还需要写:Container(Container&& other)
{
if (std::allocator_traits<allocator_type>::propagate_on_container_move_assignment::value)
{
m_alloc = std::allocator_traits<allocator_type>::select_on_container_copy_construction(
other.m_alloc
);
}
}
最佳答案
我建议研究libc++的<vector>
header 。您必须处理所有必须使用的std::lib实现者下划线。但是libc++有一个符合C++ 11的实现,用于检查。
移动分配运算符
容器移动分配运算符(operator)必须处理三种单独的可能性:
propagate_on_container_move_assignment
为true。 propagate_on_container_move_assignment
为false,lhs和rhs中的分配器比较相等。 propagate_on_container_move_assignment
为false,来自lhs和rhs的分配器比较不相等。 如果可能,这三种情况之间的决定应在编译时而不是运行时做出。具体来说,由于
propagate_on_container_move_assignment
是一个编译时间常数,因此应该在编译时在集{1}和{2,3}之间进行选择。在编译时常量上的编译时分支通常是使用tag dispatching完成的,而不是使用如所示的if语句。在所有这些情况下,都不应该使用
select_on_container_copy_construction
。该功能仅适用于容器复制构造函数。在情况1中,lhs应该首先使用lhs的分配器来释放所有已分配的内存。必须首先完成此操作,因为rhs分配器以后可能无法取消分配此内存。然后,从rhs分配器对lhs分配器进行移动分配(就像其他任何移动分配一样)。然后将内存所有权从rhs容器转移到lhs容器。如果您的容器设计不能使rhs容器处于无资源状态(糟糕的设计恕我直言),则可以通过从rhs分配器移动来为rhs容器分配新资源。
如果
propagate_on_container_move_assignment
为false,则必须在运行时在情况2和3之间进行选择,因为分配器比较是运行时操作。在情况2中,您可以执行与情况1中相同的操作,不同之处在于不要移动分配分配器。只需跳过该步骤。
在情况3中,您无法将任何内存的所有权从rhs容器转移到lhs容器。您唯一可以做的就是:
assign(make_move_iterator(rhs.begin()), make_move_iterator(rhs.end()));
请注意,在情况1中,由于已在编译时选择了算法,因此容器的
value_type
不必是MoveAssignable
或MoveInsertable
(MoveConstructible
)即可移动分配容器。但是在第2种情况下,value_type
确实必须是MoveAssignable
和MoveInsertable
(MoveConstructible
),即使它们从来没有,因为在运行时您要在2到3之间进行选择。 3需要对value_type
进行这些操作以执行assign
。移动分配运算符很容易成为实现容器最复杂的特殊成员。其余的要容易得多:
移动构造函数
move构造函数只是move构造分配器,并从rhs中窃取资源。
复制构造函数
复制构造函数从
select_on_container_copy_construction(rhs.m_alloc)
获取其分配器,然后使用该分配器为副本分配资源。复制分配运算符
复制分配运算符(operator)必须首先检查
propagate_on_container_copy_assignment
是否为true。如果是这样,并且如果lhs和rhs分配器比较不相等,则lhs必须首先释放所有内存,因为在分配分配器之后,它将无法进行分配。接下来,如果是propagate_on_container_copy_assignment
,则复制分配分配器,否则不分配。然后复制元素:assign(rhs.begin(), rhs.end());
关于c++ - 用法propagate_on_container_move_assignment的示例用法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/27471053/