File: use-emplace.rst

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (187 lines) | stat: -rw-r--r-- 6,256 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
.. title:: clang-tidy - modernize-use-emplace

modernize-use-emplace
=====================

The check flags insertions to an STL-style container done by calling the
``push_back``, ``push``, or ``push_front`` methods with an
explicitly-constructed temporary of the container element type. In this case,
the corresponding ``emplace`` equivalent methods result in less verbose and
potentially more efficient code.  Right now the check doesn't support
``insert``. It also doesn't support ``insert`` functions for associative
containers because replacing ``insert`` with ``emplace`` may result in
`speed regression <https://htmlpreview.github.io/?https://github.com/HowardHinnant/papers/blob/master/insert_vs_emplace.html>`_, but it might get support with some addition flag in the future.

The :option:`ContainersWithPushBack`, :option:`ContainersWithPush`, and
:option:`ContainersWithPushFront` options are used to specify the container
types that support the ``push_back``, ``push``, and ``push_front`` operations
respectively. The default values for these options are as follows:

* :option:`ContainersWithPushBack`: ``std::vector``, ``std::deque``, and ``std::list``.
* :option:`ContainersWithPush`: ``std::stack``, ``std::queue``, and ``std::priority_queue``.
* :option:`ContainersWithPushFront`: ``std::forward_list``, ``std::list``, and ``std::deque``.

This check also reports when an ``emplace``-like method is improperly used,
for example using ``emplace_back`` while also calling a constructor. This
creates a temporary that requires at best a move and at worst a copy. Almost all
``emplace``-like functions in the STL are covered by this, with ``try_emplace``
on ``std::map`` and ``std::unordered_map`` being the exception as it behaves
slightly differently than all the others. More containers can be added with the
:option:`EmplacyFunctions` option, so long as the container defines a
``value_type`` type, and the ``emplace``-like functions construct a
``value_type`` object.

Before:

.. code-block:: c++

    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));

After:

.. code-block:: c++

    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);

By default, the check is able to remove unnecessary ``std::make_pair`` and
``std::make_tuple`` calls from ``push_back`` calls on containers of
``std::pair`` and ``std::tuple``. Custom tuple-like types can be modified by
the :option:`TupleTypes` option; custom make functions can be modified by the
:option:`TupleMakeFunctions` option.

The other situation is when we pass arguments that will be converted to a type
inside a container.

Before:

.. code-block:: c++

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

After:

.. code-block:: c++

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


In some cases the transformation would be valid, but the code wouldn't be
exception safe. In this case the calls of ``push_back`` won't be replaced.

.. code-block:: c++

    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));

This is because replacing it with ``emplace_back`` could cause a leak of this
pointer if ``emplace_back`` would throw exception before emplacement (e.g. not
enough memory to add a new element).

For more info read item 42 - "Consider emplacement instead of insertion." of
Scott Meyers "Effective Modern C++".

The default smart pointers that are considered are ``std::unique_ptr``,
``std::shared_ptr``, ``std::auto_ptr``. To specify other smart pointers or
other classes use the :option:`SmartPointers` option.


Check also doesn't fire if any argument of the constructor call would be:

  - a bit-field (bit-fields can't bind to rvalue/universal reference)

  - a ``new`` expression (to avoid leak)

  - if the argument would be converted via derived-to-base cast.

This check requires C++11 or higher to run.

Options
-------

.. option:: ContainersWithPushBack

   Semicolon-separated list of class names of custom containers that support
   ``push_back``.

.. option:: ContainersWithPush

   Semicolon-separated list of class names of custom containers that support
   ``push``.

.. option:: ContainersWithPushFront

   Semicolon-separated list of class names of custom containers that support
   ``push_front``.

.. option:: IgnoreImplicitConstructors

    When `true`, the check will ignore implicitly constructed arguments of
    ``push_back``, e.g.

    .. code-block:: c++

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

    Default is `false`.

.. option:: SmartPointers

   Semicolon-separated list of class names of custom smart pointers.

.. option:: TupleTypes

    Semicolon-separated list of ``std::tuple``-like class names.

.. option:: TupleMakeFunctions

    Semicolon-separated list of ``std::make_tuple``-like function names. Those
    function calls will be removed from ``push_back`` calls and turned into
    ``emplace_back``.

.. option:: EmplacyFunctions

    Semicolon-separated list of containers without their template parameters
    and some ``emplace``-like method of the container. Example:
    ``vector::emplace_back``. Those methods will be checked for improper use and
    the check will report when a temporary is unnecessarily created.

Example
^^^^^^^

.. code-block:: c++

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

transforms to:

.. code-block:: c++

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

when :option:`TupleTypes` is set to ``MyTuple``, :option:`TupleMakeFunctions`
is set to ``MakeMyTuple``, and :option:`EmplacyFunctions` is set to
``vector::emplace_back``.