1. Item 41. Consider pass by value for copyable
parameters that are cheap to move and always copied.
Mitsutaka Takeda
September 30, 2015
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 1 / 25
2. Outline
...1 Chapter 8. Tweaks
...2 Item 41: Consider pass by value for copyable parameters that are cheap to
move and always copied.
...3 おまけ & 参考情報
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 2 / 25
3. Chapter 8. Tweaks
Introduction
適切な場面と適切ではない場面の判断が難しい 2 つのテクニックを紹介。
判断が難しいので"consider"。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 3 / 25
4. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
parameters that are always copied
(メンバ) 関数の定義内で copy が必要なパラメータ (setter などメンバ変数への保
持) は、性能を考慮すると、lvalue は copy、rvalue は move するべき。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 4 / 25
5. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
1st take (Overloads for lvalue and rvalue)
class Widget {
public:
void addName(const std::string& newName) {
// lvalueを取って、メンバ変数namesにcopy
names.push_back(newName);
}
void addName(std::string&& newName) {
// rvalueを取って、メンバ変数namesにmove。
names.push_back(std::move(newName));
}
private:
std::vector<std::string> names;
};
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 5 / 25
6. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
1st take (overloads for lvalue and rvalue) の問題点
" 名前を追加する"(addName) という同じコンセプトに対して、lvalue 用と
rvalue 用の 2 つの実装がある。ソース・コード量が 2 倍 => メンテナンス・コス
トが増える。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 6 / 25
7. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
2nd take (Universal reference)
class Widget {
public:
template <typename T>
void addName(T&& newName){
// Universal reference && Perfect forwarding.
names.push_back(std::forward<T>(newName));
}
private:
std::vector<std::string> names;
};
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 7 / 25
8. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
2nd take (Universal reference) の特徴
ソース・コード量は Overloads の半分。template のインスタンス化 (lvalue、
rvalue、std::string、const char*) が原因でオブジェクトのサイズは大きくなるか
も。
ヘッダ・ファイルに実装しなければいけない。
Item 30 で説明したように Universal Reference で渡せない引数がある
(initilizer list 等)。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 8 / 25
9. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
3rd take (Pass by value)
class Widget {
public:
void addName(std::string newName) {
// 引数がlvalueでもrvalueでもmove。
// newNameはcopyされたオブジェクトなのでmoveしても問題無い。
names.push_back(std::move(newName));
}
private:
std::vector<std::string> names;
};
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 9 / 25
10. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
3rd take (Pass by value) の特徴
lvalue に対して addName が呼ばれた場合は lvalue が copy される。
rvalue に対して addName が呼ばれた場合は rvalue が move される。
Overloads に対してソース・コードの量が半分。
Universal reference のような問題点がない (実装の詳細漏れ、オブジェクト・サ
イズの肥大化、理解しづらいコンパイル・エラー)
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 10 / 25
11. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
性能 (copy & move constructor 回数) の比較
lvalue rvalue
Overloads 1 copy into names 1 move into names
Universal 1 copy into names 1 move into names
By value 1 copy into newName 1 move into newName
1 move into names 1 move into names
newName は関数 Widget::addName のパラメータ。
names は Widget のメンバ変数 (std::vector<std::string>)。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 11 / 25
12. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
Back to the title
Consider pass by value for copyable parameters that are cheap to move
and always copied.
回りくどい言い方をしている 4 つの理由。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 12 / 25
13. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
1st reason
Consider pass by value for copyable parameters that are cheap to move
and always copied.
ソース・コードの量も少く、オブジェクト・コードのサイズも小さく、Universal reference
の問題点も無いが、Overloads や Universal reference と比較して性能面のコストが
1 move 分大きい (move 以外のコストについては以下で議論)。
"Consider" = 選択肢の 1 つに含める。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 13 / 25
14. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
2nd reason
Consider pass by value for copyable parameters that are cheap to move
and always copied.
パラメータが copyable で無い場合、copy する (オジェクトの所有権を caller から
callee に渡す) には move するしか方法が無い。
class Widget {
public:
// ptrの所有権をWidgetに移すにはmoveするしかない。
// const lvalue referenceはコンパイル・エラー。
// rvalue referenceの関数だけ定義すれば良い。
void setPtr(std::unique_ptr<std::string>&& ptr){
p = std::move(ptr);
}
private:
std::unique_ptr<std::string> p;
};
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 14 / 25
15. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
3rd reason
Consider pass by value for copyable parameters that are cheap to move
and always copied.
Pass by value は Overloads や Universal reference と比較して、1 move 分処理が多
い。std::array のように move と copy のコストが同じような場合はこの余計な move
が問題になる。
lvalue rvalue
Overloads 1 copy into names 1 move into names
Universal 1 copy into names 1 move into names
By value 1 copy into newName 1 move into newName
1 move into names 1 move into names
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 15 / 25
16. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
4th reason
Consider pass by value for copyable parameters that are cheap to move
and always copied.
渡したパラメータが copy されない場合があるとき、copy 不要なシーケンスでは、
Overloads や Universal reference と比較して 1 copy 分処理が多くなる。
class Widget {
public:
void addName(std::string newName) {
// By ValueではnewNameに渡された時点でcopyが発生する。
// namesにnewNameをpush_backしない場合は、OverloadsやUniversal ref
// ではcopyは発生しない。
if(newName.length() >= minLen && newName.length() <= maxLen) {
names.push_back(std::move(newName));
}
}
private:
std::vector<std::string> names;
};
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 16 / 25
17. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
constructor & assignment Part 1
"copyable && cheap-to-move && always copied" でも Pass by value が相応しくな
い場合。
オブジェクトのコピーがコンストラクタではなく代入で行なわれる場合。コンストラク
タは新しいオブジェクトを構築するための操作なのに対して、代入は構築済みのオ
ブジェクトに対する操作。代入では構築済みオブジェクトのリソースを再利用する
チャンスがある。
std::vector<T>::push_back は T のコンストラクタが実行される。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 17 / 25
18. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
constructor & assignment Part 2
Pass by value での changeTo のコスト。newPwd の copy construction でメモリ確
保と move assignemnt での text のメモリ解放。
class Password {
public:
explicit Password(std::string pwd)
: text(std::move(pwd))
{}
void changeTo(std::string newPwd){ // copy construction
text = std::move(newPwd); // move assignment
}
private:
std::string text;
};
int main()
{
std::string initPwd("Supercalifragilisticexpialidocious");
Password p(initPwd);
std::string newPassword("Beware the Jabberwock");
p.changeTo(newPassword);
return 0;
}
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 18 / 25
19. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
constructor & assignment Part 3
Overloads のコスト。newPwd の copy construction でメモリ確保 const lvalue
reference への束縛、move assignemnt での text のメモリ解放 copy assignment で
text のメモリ領域の再利用 (文字列をコピー)。copy 前に text に保存されていた文
字列 (initPwd) が新しい文字列 newPassword より長いため。
class Password {
public:
explicit Password(std::string pwd)
: text(std::move(pwd))
{}
void changeTo(const std::string& newPwd){ // bind to const lvalue reference
text = newPwd; // copy assignment
}
private:
std::string text;
};
int main() {
std::string initPwd("Supercalifragilisticexpialidocious");
Password p(initPwd);
std::string newPassword("Beware the Jabberwock"); // call newpassWord with lvalue.
p.changeTo(newPassword);
return 0;
}
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 19 / 25
20. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
cost of assignment
call with lvalue
text’s resouce is reusable text’s resource is not reusable
Overloads 0 allocation & 0 deallocation 1 allocation & 1 deallocation
both in copy asgnmt
Universal 0 allocation & 0 deallocation 1 allocation & 1 deallocation
both in copy asgnmt
By value 1 allocation in copy ctor 1 allocation in copy ctor
& 1 deallocation in move asgnmt 1 deallocation in move asgnmt
call with rvalue
text’s resouce is reusable text’s resource is not reusable
Overloads 0 allocation & 1 deallocation 1 allocation & 1 deallocation
Universal 0 allocation & 1 deallocation 1 allocation & 1 deallocation
By value 0 allocation & 1 deallocation 1 allocation & 1 deallocation
reusable : text.size() >= newPassword.size()
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 20 / 25
21. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
penalty of pass by value with assignment と IF を選択する
さいのアドバイス
.
Penalty を決定する要因
..
......
パラメータの型 (リソースの取得と解放)
関数の呼ばれ方 (lvalue or rvalue)
assignment operator の実装 (リソースの再利用)
.
推定有罪 for Pass by value
..
......
assignment を使用してコピーしている場合、Pass by value を使用しても性能的に問
題ないと確認できるまで、Overloads/Universal reference を使用する。
.
性能を追求するソフトウェアでは Pass by value は使用しない
..
......
move1 回のコストは低くても、塵も積れば。
std::string f(std::string);// pass by value
std::string g(std::string);// pass by value
std::string h(std::string);// pass by value
auto result = h(g(f(std::string("abc")))); // 4 moves
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 21 / 25
22. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
Performance 以外の問題 (Slicing)
関数が引数を多相的に扱いたい場合、パラメータはポインタ、または、参照でなけれ
ばいけない。
class Widget{};
class SpecialWidget : public Widget {};
// processWidgetはWidgetのサブ・タイプに対しても適用できる関数。
void processWidget(Widget w);// Pass by value
SpecialWidget sw;
// slicing。processWidgetはswをWidget型として扱う。
processWidget(sw);
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 22 / 25
23. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
Review
copyable & cheap-to-move & always copied なら、pass by value を使用すると、
実装が単純で、オブジェクト・コードのサイズが小さく、効率的なコードになる か
もしれない 。
assingment より constructor の方がコストが高いときがある (リソースの再利
用)。
Slicing 問題があるので多相的にオブジェクトを使用したいときは pass by value
は使用できない。
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 23 / 25
24. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
実際?
.
Overloads は組合せの爆発。
..
......
// 2引数に対して4 overloads。
void f(std::string v0, std::string v1);
void f(const std::string& v0, const std::string& v1);
void f(std::string&& v0, const std::string& v1);
void f(std::string&& v0, std::string&& v1);
.
Universal reference はヘッダ依存 & コンパイル時間の増加。
........
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 24 / 25
25. Item 41: Consider pass by value for copyable parameters that are cheap to move
and always copied.
Pass by value for constructor
Constructor で渡すパラメータはコピーされる。(メンバ変数の初期化で使用)
メンバ変数の初期化は copy constructor で行なわれる。(初期化リスト)
気にしなければいけないのは copyable かどうかと cheap-to-move だけ。
class MyClass {
public:
MyClass(std::string v0,
std::string v1)
: v0_(std::move(v0)),
v1_(std::move(v1))
{}
private:
std::string v0_;
std::string v1_;
};
Back to Basics! Essentials of Modern C++ Style@CPPCOn 2014 by Herb Sutter
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 25 / 25
26. おまけ & 参考情報
.
The evolving search for effective C++ - Keynote@Meeting C++ 2014 by Scott
Meyers
..
......
Movie
Slides
.
Back to Basics! Essentials of Modern C++ Style@CPPCOn 2014 by Herb Sutter
..
......
Movie
Slides
Mitsutaka Takeda Item 41. Consider pass by value for copyable parameters that are cheap to move and always copied.September 30, 2015 25 / 25