c++ 我能可靠地在没有赋值运算符的类型的向量中放置_back吗?

mwkjh3gx  于 2022-12-24  发布在  其他
关注(0)|答案(3)|浏览(212)

我在GCC、Clang和MSVC中做了一些测试,发现emplace_back从来不调用包含类上的赋值运算符。它只在发生重分配时调用复制或移动构造函数。这种行为是否得到了标准的某种保证?
用例是我有一些类要按顺序存储在一个数字中,这个数字只会沿着时间的推移而增长,直到整个向量被析构。我很乐意清除代码中的赋值运算符。

cqoc49vn

cqoc49vn1#

这些要求记录在cppreference.com上。
对于std::vector<T>::emplace_back

类型要求

  • T(容器的element类型)必须满足 MoveInsertableEmplaceConstructible 的要求。
    此外,std::vector有一个一般要求,即类型必须为 Erasable
    EmplaceConstructible要求该类型是可以使用给定的分配器构造的,并提供了参数。由于您使用的是默认的分配器std::allocator<T>,这只意味着该类型具有一个可访问的构造函数,并具有这些参数。
    MoveInsertable要求该类型可使用给定的分配器、使用T类型的右值构造。对于std::allocator,这意味着该类型具有可访问的移动构造函数。
    Erasable要求类型可以使用给定的分配器析构。对于std::allocator,这意味着具有可访问的析构函数。
    就是这样(除了一些关于完整类型和不完整类型的规则)。没有要求提到赋值操作符。
    但在C++11之前,类型必须是 CopyAssignableCopyConstructible,这一点已经放宽,现在除了 Erasable,要求只取决于对向量执行的操作。
7eumitmz

7eumitmz2#

是的,如果有一个可用的构造函数(或在适当的位置构造),则emplace back将调用move构造函数:

#include <iostream>
#include <vector> 

struct Pt {
    Pt() = default;
    
    Pt& operator=(Pt const& other) = delete;
    
    Pt(Pt const&) { std::cout << "copy ctor" << std::endl; }
    Pt(Pt&&){ std::cout << "move ctor" << std::endl; }
};

int main(int argc, char *argv[]) 
{
    std::vector<Pt> v;
    
    v.emplace_back(Pt{});
   
    return 0;  
}

Demo
实际的constraints applied to the type应为MoveInsertableEmplaceConstructible

odopli94

odopli943#

这就是cppreference saysemplace_back的区别:

  • T(容器的元素类型)必须满足 MoveInsertableEmplaceConstructible 的要求。

对于EmplaceConstructible,要求std::allocator_traits<A>::construct(m, p, args);有效,这是仅对实际放置元素有用的钻孔约束。

  • MoveInsertable* 似乎是重新分配所需的概念。

对于MoveInsertable,要求std::allocator_traits<A>::construct(m, p, rv);有效,其中rvT类型(即您的类型)的右值表达式。
construct的定义有点混乱,但对于大多数意图和目的来说,它似乎只是转发给构造函数的参数。
换句话说,这两个概念似乎证实了emplace_back的唯一约束是您需要提供:

  • 允许就地构造(duh)的实际构造函数
  • 发生重新分配时用于重新定位的移动构造函数(如果缺少,则为复制)

相关问题