関数パラメーターを渡すには多くの選択肢があります。値または参照で渡すことができます。参照は、const または non-const にすることができます。パラメータを移動または転送することもできます。あなたの決定は、それがインかどうかによって異なります 、そしてアウト 、インアウト 、消費 、またはフォワード 関数パラメーター。奇妙?投稿を読んでください!
ガイドラインに従って、in について話しましょう 、アウト 、出入り 、消費 、または進む パラメータ。
パラメータ受け渡し式のルール:
- F.15:シンプルで従来型の情報伝達方法を好む
- F.16:「in」パラメータについては、安価にコピーされた型を値で渡し、その他は
05
への参照で渡します - F.17:「in-out」パラメータの場合、非
11
への参照渡し - F.18:「消費」パラメータについては、
25
で渡します と37
パラメータ - F.19:「転送」パラメータの場合、
40
で渡します57
のみ パラメータ - F.20:「出力」出力値については、出力パラメータよりも戻り値を優先してください
- F.21:複数の「出力」値を返すには、タプルまたは構造体を返すことをお勧めします
- F.60:
60
を優先77
以上 「引数なし」が有効なオプションの場合
いろいろあると思いますが、ご了承ください。最初の規則 F.15 は、ガイドライン F.16 - F.21 をまとめたものです
F.15:シンプルで従来型の情報伝達方法を好む
これは、C++ コア ガイドラインの全体像です。これらは、通常のパラメータ受け渡し規則です。
これらのルールに基づいて、緑色で示されている、いわゆる高度なパラメーター受け渡しルールがいくつか追加されています。
ルールとそのバリエーションの根拠は、次のルールに従います。
F.16:「 in」パラメータで、安価にコピーされた型を値で渡し、その他は 88
への参照で渡します
in のこのルール パラメータは簡単で、例も同様です:
void f1(const string& s); // OK: pass by reference to const; always cheap void f2(string s); // bad: potentially expensive void f3(int x); // OK: Unbeatable void f4(const int& x); // bad: overhead on access in f4()
セミナーでよく聞く質問:安くコピーできるとはどういう意味ですか?ガイドラインは非常に具体的です。
- sizeof(p)> 4 * sizeof(int) の場合、パラメータ p をコピーしないでください
- sizeof(p) <3 * sizeof(int) の場合、p への const 参照を使用しないでください
これらの数値は経験に基づいていると思います.
F.17:「in-out」パラメータについては、への参照渡し93
以外
インアウト パラメーターは関数内で変更されるため、const 以外の参照を使用することは理にかなっています。
void appendElements(std::vector<int>& vec){ // append elements to vec ... }
F.18:「消費」パラメータの場合、 101
で通過 と 110
パラメータ
これは、消費する最初の高度なルールです パラメーター。パラメータを使用して関数本体内に移動する場合は、右辺値参照を使用します。以下に例を示します:
void sink(vector<int>&& v) { // sink takes ownership of whatever the argument owned // usually there might be const accesses of v here store_somewhere(std::move(v)); // usually no more use of v here; it is moved-from }
この規則には例外があります。 std::unique_ptr は、移動が安価な移動専用型であるため、移動できます。
void sink(std::unique_ptr<int> p) {
... }
...
sink(std::move(uniqPtr));
F.19:「フォワード」の場合パラメータ、129
で渡す 133
のみ パラメータ
これは、std::make_unique や std::make_shared などのファクトリ メソッドが使用するイディオムです。どちらの関数も型 T と任意の数の引数 args と forward を取ります 変わらない T のコンストラクタに渡されます。こちらをご覧ください:
template<typename T, typename... Args> // 1 std::unique_ptr<T> make_unique(Args&&... args) // 2 { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); // 3 }
このパターンは完全転送と呼ばれます:関数テンプレートが左辺値または右辺値の特性を変更せずに引数を転送する場合、それを完全転送と呼びます。
完璧な転送に関する私の以前の投稿は次のとおりです。
関数テンプレートの完全な転送を行うには、3 つのステップからなるレシピに従う必要があります。 std::make_unique のような可変個引数テンプレート (...) であってはならないので、この部分はスキップします。
<オール>F.20:「出力」出力値の場合、出力よりも戻り値を優先するパラメータ
明示的な戻り値は、関数の意図を文書化します。 out として参照するパラメータを使用する 出力値は誤解を招く可能性があります。これはインアウト値でもかまいません。関数の結果を値で返すことは、ムーブ セマンティックを暗黙的に使用する標準コンテナーにも当てはまります。
// OK: return pointers to elements with the value x vector<const int*> find_all(const vector<int>&, int x); // Bad: place pointers to elements with value x in-out void find_all(const vector<int>&, vector<const int*>& out, int x);
この規則には例外があります。移動にコストがかかるオブジェクトがある場合は、out パラメータとして参照を使用できます。
struct Package { // exceptional case: expensive-to-move object char header[16]; char load[2024 - 16]; }; Package fill(); // Bad: large return value void fill(Package&); // OK
F.21:複数の「出力」値を返すには、タプルまたは構造体
関数が複数の out を返す場合があります 価値。この場合、std::tuple または struct を使用する必要がありますが、参照でパラメーターを使用しないでください。これは非常にエラーが発生しやすいです。
// BAD: output-only parameter documented in a comment int f(const string& input, /*output only*/ string& output_data) { // ... output_data = something(); return status; } // GOOD: self-documenting tuple<int, string> f(const string& input) { // ... return make_tuple(status, something()); }
C++17 と複数の値を返す構造化バインディングを使用すると、非常に便利になります。
auto [value, success] = getValue(key); if (success){ // do something with the value;
関数 getValue はペアを返します。 success は、キーのクエリが成功したかどうかを示します。
次のルールは特別です。私にとって、このルールはよりセマンティックなルールです。とにかく。
F.60:142
156
以上 「引数なし」が有効なオプションの場合
パラメータが nullptr などの「引数なし」を取得できない場合は、T&を使用する必要があります。 T&を nullptr にすることはできません。 nullptr が可能な場合は、T* を使用してください。
std::string upperString(std::string* str){ if (str == nullptr) return std::string{}; // check for nullptr else{ ... }
オプションの引数がない場合は、確認する必要があります。
次のステップ
この投稿は約 でした 、アウト 、出入り 、消費 、進む パラメーターですが、答えるべき質問は他にもあります。シーケンスまたは所有権をどのように処理する必要がありますか?それについては次の投稿で書きます。