std::vector 与 std::move 配合使用

struct B
{
    virtual ~B() = default;

    virtual void bar() { std::cout << "B::bar\n"; }
};

struct D : B
{
    //deep copy
    std::string value;
    bool valid = true;
    char* data = nullptr;
    int size = 0;

    D() { /*std::cout << "D::D\n"; */}
    ~D() {/* std::cout << "D::~D\n"; */}

    D(const std::string& value,int size) {
        this->value = value;
        data = new char[size];
        this->size = size;
    }


    D(const D& other) {
        if (!this->data) {
            data = new char[other.size];
        }
        else if (this->size < other.size) {
            delete data;
            data = new char[size];
        }
        else {
            memset(this->data,0,this->size);
        }
        memmove(data, other.data, other.size * sizeof(char));
        this->size = other.size;
        this->value = other.value;
    }

    D(D&& other) {
        //move and reset other
        if (this->data) {
            delete data;
            data = nullptr;
        }
        this->value = std::move(other.value);
        this->data = other.data;
        this->size = other.size;
        other.size = 0;
        other.data = nullptr;
        other.valid = false;
    }
}

含有堆上数据(data 和 value)的类D实现了移动构造函数 D(D&& other) 后,与std::vector 的 push_back 和 emplace_back 配合使用,特定条件下可以提高效率。见代码和注释。


//假设对象 d 已经在别处构造好了, 并且放到 ds 以后不再使用

//!Good, 利用了D的移动构造函数
{
    D&& rd = std::move(d);
    ds.push_back(std::move(rd));
}

{
    D&& rd = std::move(d);
    ds.emplace_back(std::move(rd));
}

//!Bad,调用了拷贝构造函数
{   
    ds.push_back(rd);
}

{    
    ds.emplace_back(rd);
}

测试代码和结果:

enum CODE {
    PUSH,
    PUSH_MOVE,
    EMPLACE,
    EMPLACE_MOVE,
};

std::map<CODE, std::string> codes;

std::string fiillen(std::string& str,int len) {
    while (str.length() < len) {
        str += " ";
    }
    return str;
}

/*输出为
PUSH                 13855
PUSH_MOVE            2930
EMPLACE              9733
EMPLACE_MOVE         3759
*/

int test() {
    codes[PUSH] = "PUSH";
    codes[PUSH_MOVE] = "PUSH_MOVE";
    codes[EMPLACE] = "EMPLACE";
    codes[EMPLACE_MOVE] = "EMPLACE_MOVE";
    INT64 time = 0;
    INT64 bytes = 1000;
    INT64 count = 100;

    auto test = [&](int code) {

        /*
        在外部构造 d,避免对 ds 操作的干扰
        */
        D d("", bytes);       
        std::vector<D> ds;
        auto t1 = steady_clock::now();
        for (int i = 0; i < 10; i++) {
            switch (code)
            {
            case PUSH:
                ds.push_back(d);
                break;
            case EMPLACE:
                ds.emplace_back(d);
                break;
            case PUSH_MOVE: {
                D&& rd = std::move(d);
                ds.push_back(std::move(rd));
            }
                break;
            case EMPLACE_MOVE: {
                D&& rd = std::move(d);
                ds.emplace_back(std::move(rd));
            }
                break;

            default:
                break;
            }
        }
        auto t2 = steady_clock::now();
        auto tt = duration_cast<nanoseconds>(t2 - t1);
        time += tt.count();
    };

    for (int code = 0; code < 4; code++) {
        time = 0;
        for (int i = 0; i < count; i++) {
            test(code);
        }
        std::cout << fiillen(codes[(CODE)code],20) << " " << time / count << std::endl;
    }   
    return 0;
}

从测试结果来看移动构造由于节省了很多拷贝 data 的时间, push_back 和 emplace_back 得到了速度上的优化,其他 std 容器类比一下应该具有同样特性。

需要注意的一点是以下代码不能获得这种优化,在 emplace_back(push_back)时,调用的还是拷贝构造函数。

D&& rd = std::move(d);
ds.emplace_back(rd);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值