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
时。