167 lines
4.5 KiB
ReStructuredText
167 lines
4.5 KiB
ReStructuredText
|
.. title:: clang-tidy - modernize-pass-by-value
|
|||
|
|
|||
|
modernize-pass-by-value
|
|||
|
=======================
|
|||
|
|
|||
|
With move semantics added to the language and the standard library updated with
|
|||
|
move constructors added for many types it is now interesting to take an
|
|||
|
argument directly by value, instead of by const-reference, and then copy. This
|
|||
|
check allows the compiler to take care of choosing the best way to construct
|
|||
|
the copy.
|
|||
|
|
|||
|
The transformation is usually beneficial when the calling code passes an
|
|||
|
*rvalue* and assumes the move construction is a cheap operation. This short
|
|||
|
example illustrates how the construction of the value happens:
|
|||
|
|
|||
|
.. code-block:: c++
|
|||
|
|
|||
|
void foo(std::string s);
|
|||
|
std::string get_str();
|
|||
|
|
|||
|
void f(const std::string &str) {
|
|||
|
foo(str); // lvalue -> copy construction
|
|||
|
foo(get_str()); // prvalue -> move construction
|
|||
|
}
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Currently, only constructors are transformed to make use of pass-by-value.
|
|||
|
Contributions that handle other situations are welcome!
|
|||
|
|
|||
|
|
|||
|
Pass-by-value in constructors
|
|||
|
-----------------------------
|
|||
|
|
|||
|
Replaces the uses of const-references constructor parameters that are copied
|
|||
|
into class fields. The parameter is then moved with `std::move()`.
|
|||
|
|
|||
|
Since ``std::move()`` is a library function declared in `<utility>` it may be
|
|||
|
necessary to add this include. The check will add the include directive when
|
|||
|
necessary.
|
|||
|
|
|||
|
.. code-block:: c++
|
|||
|
|
|||
|
#include <string>
|
|||
|
|
|||
|
class Foo {
|
|||
|
public:
|
|||
|
- Foo(const std::string &Copied, const std::string &ReadOnly)
|
|||
|
- : Copied(Copied), ReadOnly(ReadOnly)
|
|||
|
+ Foo(std::string Copied, const std::string &ReadOnly)
|
|||
|
+ : Copied(std::move(Copied)), ReadOnly(ReadOnly)
|
|||
|
{}
|
|||
|
|
|||
|
private:
|
|||
|
std::string Copied;
|
|||
|
const std::string &ReadOnly;
|
|||
|
};
|
|||
|
|
|||
|
std::string get_cwd();
|
|||
|
|
|||
|
void f(const std::string &Path) {
|
|||
|
// The parameter corresponding to 'get_cwd()' is move-constructed. By
|
|||
|
// using pass-by-value in the Foo constructor we managed to avoid a
|
|||
|
// copy-construction.
|
|||
|
Foo foo(get_cwd(), Path);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
If the parameter is used more than once no transformation is performed since
|
|||
|
moved objects have an undefined state. It means the following code will be left
|
|||
|
untouched:
|
|||
|
|
|||
|
.. code-block:: c++
|
|||
|
|
|||
|
#include <string>
|
|||
|
|
|||
|
void pass(const std::string &S);
|
|||
|
|
|||
|
struct Foo {
|
|||
|
Foo(const std::string &S) : Str(S) {
|
|||
|
pass(S);
|
|||
|
}
|
|||
|
|
|||
|
std::string Str;
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
Known limitations
|
|||
|
^^^^^^^^^^^^^^^^^
|
|||
|
|
|||
|
A situation where the generated code can be wrong is when the object referenced
|
|||
|
is modified before the assignment in the init-list through a "hidden" reference.
|
|||
|
|
|||
|
Example:
|
|||
|
|
|||
|
.. code-block:: c++
|
|||
|
|
|||
|
std::string s("foo");
|
|||
|
|
|||
|
struct Base {
|
|||
|
Base() {
|
|||
|
s = "bar";
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
struct Derived : Base {
|
|||
|
- Derived(const std::string &S) : Field(S)
|
|||
|
+ Derived(std::string S) : Field(std::move(S))
|
|||
|
{ }
|
|||
|
|
|||
|
std::string Field;
|
|||
|
};
|
|||
|
|
|||
|
void f() {
|
|||
|
- Derived d(s); // d.Field holds "bar"
|
|||
|
+ Derived d(s); // d.Field holds "foo"
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Note about delayed template parsing
|
|||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|||
|
|
|||
|
When delayed template parsing is enabled, constructors part of templated
|
|||
|
contexts; templated constructors, constructors in class templates, constructors
|
|||
|
of inner classes of template classes, etc., are not transformed. Delayed
|
|||
|
template parsing is enabled by default on Windows as a Microsoft extension:
|
|||
|
`Clang Compiler User’s Manual - Microsoft extensions`_.
|
|||
|
|
|||
|
Delayed template parsing can be enabled using the `-fdelayed-template-parsing`
|
|||
|
flag and disabled using `-fno-delayed-template-parsing`.
|
|||
|
|
|||
|
Example:
|
|||
|
|
|||
|
.. code-block:: c++
|
|||
|
|
|||
|
template <typename T> class C {
|
|||
|
std::string S;
|
|||
|
|
|||
|
public:
|
|||
|
= // using -fdelayed-template-parsing (default on Windows)
|
|||
|
= C(const std::string &S) : S(S) {}
|
|||
|
|
|||
|
+ // using -fno-delayed-template-parsing (default on non-Windows systems)
|
|||
|
+ C(std::string S) : S(std::move(S)) {}
|
|||
|
};
|
|||
|
|
|||
|
.. _Clang Compiler User’s Manual - Microsoft extensions: http://clang.llvm.org/docs/UsersManual.html#microsoft-extensions
|
|||
|
|
|||
|
.. seealso::
|
|||
|
|
|||
|
For more information about the pass-by-value idiom, read: `Want Speed? Pass by Value`_.
|
|||
|
|
|||
|
.. _Want Speed? Pass by Value: https://web.archive.org/web/20140205194657/http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
|
|||
|
|
|||
|
Options
|
|||
|
-------
|
|||
|
|
|||
|
.. option:: IncludeStyle
|
|||
|
|
|||
|
A string specifying which include-style is used, `llvm` or `google`. Default
|
|||
|
is `llvm`.
|
|||
|
|
|||
|
.. option:: ValuesOnly
|
|||
|
|
|||
|
When non-zero, the check only warns about copied parameters that are already
|
|||
|
passed by value. Default is `0`.
|