移动语义 ≠ 高效

移动让复杂对象的值语义也有了高效的可能性,但还是要看数据结构的内存布局

DEMO

#include<bits/stdc++.h>

int main() {
    constexpr size_t MAXN = 1e5;
    std::vector<int> a(MAXN);
    auto b = a;
    for(int count = 1e6; count; --count) {
        std::swap(a,b);
    }
    return 0;
}

很快?那下一个

#include<bits/stdc++.h>

int main() {
    constexpr size_t MAXN = 1e5;
    std::array<int,MAXN> a;
    auto b = a; 
    for(int count = 1e6; count; --count) {
        std::swap(a,b);
    }
    return 0;
}

慢成一坨了

  1. std::swap使用到std::move 实现
  2. 右值的存在只是影响重载决议,不要过于信任其移动语义的性能
  3. 移动所谓的窃取资源,只是相当于安全的浅拷贝,对于类似std::array这种只有栈上数据的类,窃取是没意义的
  4. 多使用类似std::vector的设计,把数据放在堆上,栈只保留访问句柄,这样才能高效移动(句柄)

随想1

对于一般的类来说,右值move到值语义的接口认为是几乎不要成本,但是性能关键的时候不一定好使

比如常见的构造函数中Klass(string s): _s(move(s))

但是遇到继承链较长的类,s会引发多次的移动

一种妥协的解决方法是使用using构造函数(最初以为只是语法糖),但是这样基本让构造函数没什么扩展性可言

目前没有找到更好的办法能满足清晰的值语义接口又不想花费更多无谓操作成本


随想2

我觉得C++一个强大之处在于对POD的支持,连续的内存分布对性能和C兼容性的重要性就不必多说了

但是move对POD是完全的无意义,确实挺矛盾的感觉

与其说移动是一个让值语义也能高效使用的机制,不如说是一个解决栈上所有权问题(smart_val?),只是顺手提供了大部分情况下值语义更为实用高效的特性

发表评论

邮箱地址不会被公开。 必填项已用*标注