當這些東西跟 STL, return value optimization (RVO) 等等的東西融合時
就讓事情變得很複雜了,
因此本文紀錄了一些我遇到的 case,希望未來也會繼續更新
把資料 move+insert 到 map 裡面
目的:比較 make_tuple vs forward_as_tuple 以及是否使用 move並盡量減少 move, copy 的數量?
感謝強者我同學小新提供這個討論
#include <tuple>
#include <iotsream>
using namespace std;
struct A {
A() { cout << "Ctor" << endl; }
A(const A&) { cout << "Copy" << endl; }
A(A&&) { cout << "Move" << endl; }
};
int main() {
A a;
map<int,tuple<A>> m;
cout << "1" << endl;
m.insert(make_pair(1, make_tuple(a)));
cout << "2" << endl;
m.insert(make_pair(2, make_tuple(move(a))));
cout << "3" << endl;
m.insert(make_pair(3, forward_as_tuple(a)));
cout << "4" << endl;
m.insert(make_pair(4, forward_as_tuple(move(a))));
cout << "5" << endl;
m.emplace(5, make_tuple(move(a)));
cout << "6" << endl;
m.emplace(6, forward_as_tuple(move(a)));
return 0;
}
實際執行結果如下 gcc version 8.1.1 20180531 (GCC)
Ctor
1
Copy
Move
Move
2
Move
Move
Move
3
Copy
4
Move
5
Move
Move
6
Move
- make_tuple(a) copy 了一次,之後 make_pair, insert 各自 move 了一次。因為都是 rvalue。這邊的 make_pair 等效於 pair<int, tuple<A>>(...),所以需要 move。
- 只是把 1 的第一個 copy 改成 move。
- forward_as_tuple(a) 等效於 make_tuple<A&>(a),之後 make_pair 是 pair<int, tuple<A&>> 也是 reference type,所以不用 move/copy,也就是 copy 是在 insert 發生的。
- forward_as_tuple(move(a)) 等效於 make_tuple<A&&>(move(a)),跟 3 類似,move 也是在 insert 發生的。
- 使用了 C++11 的 emplace,跟 2 一樣,但是省去了 make_pair 的 overhead。
- 應該是成本最低的方法,跟 4 一樣,但是省去了 make_pair 的 overhead。
因為 a 是 lvalue 的關係,使用 move() 才有機會避免 copy constructor
因此沒有嘗試把 1, 3 用 emplace 改寫
沒有留言:
張貼留言