Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当涉及分配器时,是否有类似于复制和交换的习惯用法?_C++_C++11_Allocator - Fatal编程技术网

C++ 当涉及分配器时,是否有类似于复制和交换的习惯用法?

C++ 当涉及分配器时,是否有类似于复制和交换的习惯用法?,c++,c++11,allocator,C++,C++11,Allocator,关于复制和交换习惯用法,有几个很好的答案,例如,和。复制和移动分配的基本习惯用法如下所示: T& T::operator=(T other) { this->swap(other); return *this; } 此赋值同时适用于复制和移动赋值,因为other是复制还是移动,取决于赋值的右侧是左值还是右值 现在让有状态分配器进入图片:如果T在分配器类型上参数化,例如std::vector,则上述习惯用法并不总是有效!具体而言,std::allocator\u t

关于复制和交换习惯用法,有几个很好的答案,例如,和。复制和移动分配的基本习惯用法如下所示:

T& T::operator=(T other) {
    this->swap(other);
    return *this;
}
此赋值同时适用于复制和移动赋值,因为
other
是复制还是移动,取决于赋值的右侧是左值还是右值

现在让有状态分配器进入图片:如果
T
在分配器类型上参数化,例如
std::vector
,则上述习惯用法并不总是有效!具体而言,
std::allocator\u traits
包含三种类型,指示是否应传播分配器:

  • std::分配器特性::在容器上传播\u复制\u分配
  • std::分配器特性::在容器上传播\u移动\u分配
  • std::分配器特性::在容器交换上传播
  • 这三个特征的默认值是
    std::false_type
    (参见20.6.8.1[allocator.traits.types]第7、8和9段)。如果这些特征中的任何一个是
    std::false_type
    ,并且分配器是有状态的,并且有可能比较不相等,那么普通的复制和交换习惯用法就不起作用。对于副本分配,修复相当简单:

    T& T::operator= (T const& other) {
        T(other, this->get_allocator()).same_allocator_swap(*this);
        return *this;
    }
    
    也就是说,首先复制对象以提供LHS的分配器对象,然后使用一个函数交换成员,如果两个对象使用相同的分配器,即当
    other.get\u allocator()==this->get\u allocator()
    时,该函数会起作用

    移动指定时,如果可以移动RHS,则最好不要复制RHS。如果分配器相同,则可以移动RHS。否则,需要使用适当的分配器复制对象,从而产生如下赋值运算符

    T& T::operator= (T&& other) {
        T(std::move(other), this->get_allocator()).same_allocator_swap(*this);
        return *this;
    }
    
    这里的方法是在传递分配器的同时移动并构造一个临时变量。这样做假定类型
    T
    确实有一个“移动构造函数”,为对象状态使用
    T&
    ,并使用分配器指定要使用的分配器。移动构造函数的任务是根据不同或相同的分配器进行复制或移动

    由于第一个参数的传递方式不同,因此复制和移动赋值不能仅折叠为一个版本的赋值运算符。因此,他们需要将自己的参数作为引用,并需要显式复制或移动参数,从而抑制复制省略的可能性


    当涉及分配器时,有没有更好的方法来处理赋值运算符?

    您似乎暗示经典的复制/交换习惯用法确实适用于所有的
    传播特性都不是假的情况。我认为情况并非如此。例如,考虑:

    std::allocator_traits<A>::propagate_on_container_copy_assignment::value == true
    std::allocator_traits<A>::propagate_on_container_swap::value == false
    
    std::分配器\u特征::在容器上传播\u复制\u分配::值==true
    std::allocator\u traits::在容器上传播\u\u交换::值==false
    
    经典的复制/交换惯用赋值运算符不会将分配器从rhs传播到lhs,而是在两个分配器状态不相等时进入未定义行为的状态

    您对copy assignment操作符的重写也不能处理这两种特性的组合,因为它从不在copy assignment上传播分配器

    我认为,如果想要遵循std::containers的规则,就不建议使用copy/swap习惯用法

    我为自己保存了一份“分配者行为”备忘单,其中描述了这些成员的行为(用英语而不是标准的eze)

    复制分配运算符

    如果
    propagate\u on\u container\u copy\u assignment::value
    为true,则copy分配分配器。在这种情况下,如果分配器在分配之前不相等,则首先释放lhs上的所有内存。然后继续复制赋值,而不转移任何内存所有权。例如,
    this->assign(rhs.begin(),rhs.end())

    移动分配运算符

  • 如果
    propagate\u on\u container\u move\u assignment::value
    为true,则释放lhs上的所有内存,移动分配程序,然后将内存所有权从rhs转移到lhs

  • 如果
    propagate\u on\u container\u move\u assignment::value
    为false,且两个分配器相等,则释放lhs上的所有内存,然后将内存所有权从rhs转移到lhs

  • 如果
    propagate\u on\u container\u move\u assignment::value
    为false,且两个分配器不相等,则将assign作为
    this->assign(make\u move\u迭代器(rhs.begin()),make\u move\u迭代器(rhs.end())

  • 这些描述旨在实现尽可能高的性能,同时遵守容器和分配器的C++11规则。只要有可能,内存资源(如
    vector capacity()
    )要么从rhs传输,要么在lhs上重新使用

    复制/交换习惯用法总是在lhs上丢弃内存资源(例如
    向量容量()
    ),而不是在lhs上释放这些资源之前,以临时方式抢先分配这些资源

    完整性:

    交换


    如果
    propagate\u on_container\u swap::value
    为true,则交换分配器。无论如何,交换内存所有权。如果
    propagate\u on_container\u swap::value
    为false且分配器不相等,则行为未定义。

    好的,我的尝试显然有点不完整。您的描述不会产生强异常安全分配甚至对于副本分配(至少在某些条件下)。答案还意味着,没有已知的合理简单的配方可以利用在其他方法中实现的功能。同意基本异常安全性。即