读书人

采用C++11的右值引用来避免拷贝,没有达

发布时间: 2012-05-28 17:59:33 作者: rapoo

采用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是优先匹配有成员函数的那个版本的。。

读书人网 >C++

热点推荐