我在GCC、Clang和MSVC中做了一些测试,发现emplace_back从来不调用包含类上的赋值运算符。它只在发生重分配时调用复制或移动构造函数。这种行为是否得到了标准的某种保证?用例是我有一些类要按顺序存储在一个数字中,这个数字只会沿着时间的推移而增长,直到整个向量被析构。我很乐意清除代码中的赋值运算符。
emplace_back
cqoc49vn1#
这些要求记录在cppreference.com上。对于std::vector<T>::emplace_back:
std::vector<T>::emplace_back
类型要求
T
element
MoveInsertable
EmplaceConstructible
std::vector
Erasable
std::allocator<T>
std::allocator
CopyAssignable
CopyConstructible
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应为MoveInsertable和EmplaceConstructible
odopli943#
这就是cppreference says和emplace_back的区别:
对于EmplaceConstructible,要求std::allocator_traits<A>::construct(m, p, args);有效,这是仅对实际放置元素有用的钻孔约束。
std::allocator_traits<A>::construct(m, p, args);
对于MoveInsertable,要求std::allocator_traits<A>::construct(m, p, rv);有效,其中rv是T类型(即您的类型)的右值表达式。construct的定义有点混乱,但对于大多数意图和目的来说,它似乎只是转发给构造函数的参数。换句话说,这两个概念似乎证实了emplace_back的唯一约束是您需要提供:
std::allocator_traits<A>::construct(m, p, rv);
rv
construct
3条答案
按热度按时间cqoc49vn1#
这些要求记录在cppreference.com上。
对于
std::vector<T>::emplace_back
:类型要求
T
(容器的element
类型)必须满足MoveInsertable
和EmplaceConstructible
的要求。此外,
std::vector
有一个一般要求,即类型必须为Erasable
。EmplaceConstructible要求该类型是可以使用给定的分配器构造的,并提供了参数。由于您使用的是默认的分配器
std::allocator<T>
,这只意味着该类型具有一个可访问的构造函数,并具有这些参数。MoveInsertable要求该类型可使用给定的分配器、使用
T
类型的右值构造。对于std::allocator
,这意味着该类型具有可访问的移动构造函数。Erasable要求类型可以使用给定的分配器析构。对于
std::allocator
,这意味着具有可访问的析构函数。就是这样(除了一些关于完整类型和不完整类型的规则)。没有要求提到赋值操作符。
但在C++11之前,类型必须是
CopyAssignable
和CopyConstructible
,这一点已经放宽,现在除了Erasable
,要求只取决于对向量执行的操作。7eumitmz2#
是的,如果有一个可用的构造函数(或在适当的位置构造),则emplace back将调用move构造函数:
Demo
实际的constraints applied to the type应为MoveInsertable和EmplaceConstructible
odopli943#
这就是cppreference says和
emplace_back
的区别:T
(容器的元素类型)必须满足 MoveInsertable 和 EmplaceConstructible 的要求。对于EmplaceConstructible,要求
std::allocator_traits<A>::construct(m, p, args);
有效,这是仅对实际放置元素有用的钻孔约束。对于MoveInsertable,要求
std::allocator_traits<A>::construct(m, p, rv);
有效,其中rv
是T
类型(即您的类型)的右值表达式。construct
的定义有点混乱,但对于大多数意图和目的来说,它似乎只是转发给构造函数的参数。换句话说,这两个概念似乎证实了
emplace_back
的唯一约束是您需要提供: