modernize-use-emplace

此检查标记对 STL 风格容器的插入操作,这些操作是通过调用 push_backpushpush_front 方法,并使用容器元素类型的显式构造的临时对象来完成的。在这种情况下,相应的 emplace 等效方法将导致更简洁且可能更有效的代码。目前,此检查不支持 insert。它也不支持关联容器的 insert 函数,因为用 emplace 替换 insert 可能导致 速度下降,但它可能在未来通过添加一些标志来获得支持。

ContainersWithPushBackContainersWithPushContainersWithPushFront 选项用于指定分别支持 push_backpushpush_front 操作的容器类型。这些选项的默认值如下所示

此检查还报告当 emplace 类方法使用不当时,例如在调用构造函数的同时使用 emplace_back。这将创建一个临时对象,该对象在最好的情况下需要移动,在最坏的情况下需要复制。STL 中几乎所有 emplace 类函数都涵盖了这一点,std::mapstd::unordered_map 上的 try_emplace 是例外,因为它的行为与其他函数略有不同。可以使用 EmplacyFunctions 选项添加更多容器,只要容器定义了 value_type 类型,并且 emplace 类函数构造了一个 value_type 对象。

之前

std::vector<MyClass> v;
v.push_back(MyClass(21, 37));
v.emplace_back(MyClass(21, 37));

std::vector<std::pair<int, int>> w;

w.push_back(std::pair<int, int>(21, 37));
w.push_back(std::make_pair(21L, 37L));
w.emplace_back(std::make_pair(21L, 37L));

之后

std::vector<MyClass> v;
v.emplace_back(21, 37);
v.emplace_back(21, 37);

std::vector<std::pair<int, int>> w;
w.emplace_back(21, 37);
w.emplace_back(21L, 37L);
w.emplace_back(21L, 37L);

默认情况下,此检查能够从 std::pairstd::tuple 容器的 push_back 调用中删除不必要的 std::make_pairstd::make_tuple 调用。可以使用 TupleTypes 选项修改自定义元组类型;可以使用 TupleMakeFunctions 选项修改自定义创建函数。

另一种情况是,当我们传递将被转换为容器内类型的参数时。

之前

std::vector<boost::optional<std::string> > v;
v.push_back("abc");

之后

std::vector<boost::optional<std::string> > v;
v.emplace_back("abc");

在某些情况下,转换是有效的,但代码不会是异常安全的。在这种情况下,push_back 的调用将不会被替换。

std::vector<std::unique_ptr<int>> v;
v.push_back(std::unique_ptr<int>(new int(0)));
auto *ptr = new int(1);
v.push_back(std::unique_ptr<int>(ptr));

这是因为用 emplace_back 替换它可能会导致此指针泄漏,如果 emplace_back 在放置之前抛出异常(例如,没有足够的内存添加新元素)。

有关更多信息,请阅读 Scott Meyers 的“Effective Modern C++”中的第 42 项 -“考虑使用放置而不是插入”。

默认情况下,考虑的智能指针是 std::unique_ptrstd::shared_ptrstd::auto_ptr。要指定其他智能指针或其他类,请使用 SmartPointers 选项。

如果构造函数调用的任何参数为,则检查也不会触发

  • 位域(位域不能绑定到右值/通用引用)

  • 一个 new 表达式(为避免泄漏)

  • 如果该参数将通过派生类到基类转换进行转换。

此检查需要 C++11 或更高版本才能运行。

选项

ContainersWithPushBack

支持 push_back 的自定义容器的类名称,以分号分隔。

ContainersWithPush

支持 push 的自定义容器的类名称,以分号分隔。

ContainersWithPushFront

支持 push_front 的自定义容器的类名称,以分号分隔。

IgnoreImplicitConstructors

当为 true 时,此检查将忽略 push_back 的隐式构造的参数,例如

std::vector<std::string> v;
v.push_back("a"); // Ignored when IgnoreImplicitConstructors is `true`.

默认值为 false

SmartPointers

自定义智能指针的类名称,以分号分隔。

TupleTypes

std::tuple 类名称,以分号分隔。

TupleMakeFunctions

std::make_tuple 函数名称,以分号分隔。这些函数调用将从 push_back 调用中删除,并转换为 emplace_back

EmplacyFunctions

容器(不带其模板参数)和容器的某些 emplace 类方法,以分号分隔。示例:vector::emplace_back。这些方法将被检查以确保使用得当,并且检查将在创建不必要的临时对象时报告。

示例

std::vector<MyTuple<int, bool, char>> x;
x.push_back(MakeMyTuple(1, false, 'x'));
x.emplace_back(MakeMyTuple(1, false, 'x'));

转换为

std::vector<MyTuple<int, bool, char>> x;
x.emplace_back(1, false, 'x');
x.emplace_back(1, false, 'x');

TupleTypes 设置为 MyTupleTupleMakeFunctions 设置为 MakeMyTupleEmplacyFunctions 设置为 vector::emplace_back 时。