modernize-use-emplace¶
此检查标记对 STL 风格容器的插入操作,这些操作是通过调用 push_back、push 或 push_front 方法,并使用容器元素类型的显式构造的临时对象来完成的。在这种情况下,相应的 emplace 等效方法将导致更简洁且可能更有效的代码。目前,此检查不支持 insert。它也不支持关联容器的 insert 函数,因为用 emplace 替换 insert 可能导致 速度下降,但它可能在未来通过添加一些标志来获得支持。
ContainersWithPushBack、ContainersWithPush 和 ContainersWithPushFront 选项用于指定分别支持 push_back、push 和 push_front 操作的容器类型。这些选项的默认值如下所示
ContainersWithPushBack:std::vector、std::deque和std::list。ContainersWithPush:std::stack、std::queue和std::priority_queue。ContainersWithPushFront:std::forward_list、std::list和std::deque。
此检查还报告当 emplace 类方法使用不当时,例如在调用构造函数的同时使用 emplace_back。这将创建一个临时对象,该对象在最好的情况下需要移动,在最坏的情况下需要复制。STL 中几乎所有 emplace 类函数都涵盖了这一点,std::map 和 std::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::pair 和 std::tuple 容器的 push_back 调用中删除不必要的 std::make_pair 和 std::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_ptr、std::shared_ptr、std::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 设置为 MyTuple、TupleMakeFunctions 设置为 MakeMyTuple 且 EmplacyFunctions 设置为 vector::emplace_back 时。