1.. title:: clang-tidy - modernize-pass-by-value
2
3modernize-pass-by-value
4=======================
5
6With move semantics added to the language and the standard library updated with
7move constructors added for many types it is now interesting to take an
8argument directly by value, instead of by const-reference, and then copy. This
9check allows the compiler to take care of choosing the best way to construct
10the copy.
11
12The transformation is usually beneficial when the calling code passes an
13*rvalue* and assumes the move construction is a cheap operation. This short
14example illustrates how the construction of the value happens:
15
16.. code-block:: c++
17
18    void foo(std::string s);
19    std::string get_str();
20
21    void f(const std::string &str) {
22      foo(str);       // lvalue  -> copy construction
23      foo(get_str()); // prvalue -> move construction
24    }
25
26.. note::
27
28   Currently, only constructors are transformed to make use of pass-by-value.
29   Contributions that handle other situations are welcome!
30
31
32Pass-by-value in constructors
33-----------------------------
34
35Replaces the uses of const-references constructor parameters that are copied
36into class fields. The parameter is then moved with `std::move()`.
37
38Since ``std::move()`` is a library function declared in `<utility>` it may be
39necessary to add this include. The check will add the include directive when
40necessary.
41
42.. code-block:: c++
43
44     #include <string>
45
46     class Foo {
47     public:
48    -  Foo(const std::string &Copied, const std::string &ReadOnly)
49    -    : Copied(Copied), ReadOnly(ReadOnly)
50    +  Foo(std::string Copied, const std::string &ReadOnly)
51    +    : Copied(std::move(Copied)), ReadOnly(ReadOnly)
52       {}
53
54     private:
55       std::string Copied;
56       const std::string &ReadOnly;
57     };
58
59     std::string get_cwd();
60
61     void f(const std::string &Path) {
62       // The parameter corresponding to 'get_cwd()' is move-constructed. By
63       // using pass-by-value in the Foo constructor we managed to avoid a
64       // copy-construction.
65       Foo foo(get_cwd(), Path);
66     }
67
68
69If the parameter is used more than once no transformation is performed since
70moved objects have an undefined state. It means the following code will be left
71untouched:
72
73.. code-block:: c++
74
75  #include <string>
76
77  void pass(const std::string &S);
78
79  struct Foo {
80    Foo(const std::string &S) : Str(S) {
81      pass(S);
82    }
83
84    std::string Str;
85  };
86
87
88Known limitations
89^^^^^^^^^^^^^^^^^
90
91A situation where the generated code can be wrong is when the object referenced
92is modified before the assignment in the init-list through a "hidden" reference.
93
94Example:
95
96.. code-block:: c++
97
98   std::string s("foo");
99
100   struct Base {
101     Base() {
102       s = "bar";
103     }
104   };
105
106   struct Derived : Base {
107  -  Derived(const std::string &S) : Field(S)
108  +  Derived(std::string S) : Field(std::move(S))
109     { }
110
111     std::string Field;
112   };
113
114   void f() {
115  -  Derived d(s); // d.Field holds "bar"
116  +  Derived d(s); // d.Field holds "foo"
117   }
118
119
120Note about delayed template parsing
121^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
122
123When delayed template parsing is enabled, constructors part of templated
124contexts; templated constructors, constructors in class templates, constructors
125of inner classes of template classes, etc., are not transformed. Delayed
126template parsing is enabled by default on Windows as a Microsoft extension:
127`Clang Compiler User’s Manual - Microsoft extensions`_.
128
129Delayed template parsing can be enabled using the `-fdelayed-template-parsing`
130flag and disabled using `-fno-delayed-template-parsing`.
131
132Example:
133
134.. code-block:: c++
135
136   template <typename T> class C {
137     std::string S;
138
139   public:
140 =  // using -fdelayed-template-parsing (default on Windows)
141 =  C(const std::string &S) : S(S) {}
142
143 +  // using -fno-delayed-template-parsing (default on non-Windows systems)
144 +  C(std::string S) : S(std::move(S)) {}
145   };
146
147.. _Clang Compiler User’s Manual - Microsoft extensions: https://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
148
149.. seealso::
150
151  For more information about the pass-by-value idiom, read: `Want Speed? Pass by Value`_.
152
153  .. _Want Speed? Pass by Value: https://web.archive.org/web/20140205194657/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
154
155Options
156-------
157
158.. option:: IncludeStyle
159
160   A string specifying which include-style is used, `llvm` or `google`. Default
161   is `llvm`.
162
163.. option:: ValuesOnly
164
165   When `true`, the check only warns about copied parameters that are already
166   passed by value. Default is `false`.
167