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