采用C++11的右值引用来避免拷贝,没有达到我的期望.为什么?
我知道STL的算法对象sort里面,交换两个变量的时候是用的swap.
swap是非常昂贵的,因为要先构造一个temp对象,然后做两次赋值,因此对于复杂的对象而言,就调用了一次拷贝构造函数和两次赋值operator=.
那么C++11的move语义是不是能帮我完全避免这个问题呢? 我试了一下,如下的代码:
- C/C++ code
struct s{ int i; s():i(11){cout<<"default ctor"<<endl;} s(int ii):i(ii){cout<<"explicit ctor"<<endl;} s(const s& ss){ i=ss.i; cout<<"copy ctor"<<endl; } s& operator=(const s& ss){ i=ss.i; cout<<__FUNCTION__<<endl; return *this; } s(s&&ss){ i=ss.i; cout<<"move semantic"<<endl; }};void swap(s& a, s& b)//重载swap函数,我希望被std::sort调用。{ cout<<"overloaded swap"<<endl; s tmp(move(a)); // 对象a被移动到对象tmp,a被清空 a = move(b); // 对象b被移动到对象a,b被清空 b = move(tmp); // 对象tmp被移动到对象b}int main(void){ s ps[4]={12,13,14,9}; vector<s> vs(ps,ps+_countof(ps)); cout<<"===================="<<endl; sort(vs.begin(),vs.end(), [](const s& t1, const s& t2) {return t1.i<t2.i;}); for_each(vs.begin(),vs.end(), [](const s& ss){cout<<ss.i<<endl;}); return 0; }实际测试的结果令我非常失望:
(1) 程序并没有调用到我特化出来的swap版本。这是为什么?
(2) 和没有转移构造函数相比,operator=()的调用一个也没有少。只是把所有的拷贝构造函数的调用换成了转移构造函数而已。
为什么Operator=()没有被避免? 我已经定义了转移构造函数了啊?
各位帮忙解惑啊。谢谢。
[解决办法]
换编译器。
[解决办法]
换编译器。
[解决办法]
用GCC 4.7.0编译器
[解决办法]
你都没定义move语义的构造函数和赋值函数,怎么可能会move呢?你让编译器情以何堪啊
[解决办法]
(1) 标准没说 std::sort 的实现要用 swap 进行交换,具体实现可以完全不用 swap,仍然符合标准。
(2) move semantics 不表明 operator= 就不用调用了,只是说明,在条件允许的情况下,尽可能调用 move ctor 和 move assignment operator.
另外,你的 s 类没用提供 move assignment operator.
还有,像你实现的 swap,即便调用了,a = ...; b = ...; 这种操作也一定会导致 s::operator= 的调用,否则编译器如何解释 a = ...; 这句话?
[解决办法]
额。。。说句题外话。。想提高swap效率,可以自己实现一个swap的成员函数,swap是优先匹配有成员函数的那个版本的。。