C++11 移动语义 和 完美转发

1、左值和右值

在C++11中可以取地址(有变量名)的就是左值;不能取地址(没有变量名)的就是右值
举例:
int a = fun(b + c)
a是左值,有变量名且可以取地址
fun(b+c)是右值(将亡值)

2、右值引用 和 移动语义(std::move)

引入右值引用的目的就是为了减少内存拷贝,优化程序性能
std::move 就是将一个左值变量强行转换为右值引用,相当于static_cast<T&&>(l_reference)
std::move 并不会真正地移动对象,真正的移动操作是在RD自己实现的移动构造函数中

#include <string.h>
#include <iostream>

class Test
{
    public:
        Test()
        {
            buffer = new char[1024];
            datasize = 1024;
        }
        Test(const Test& test)
        {
            // 调用深拷贝
            printf("l copy construct\n");
            this->buffer = new char[test.datasize];
            memcpy(this->buffer, test.buffer, test.datasize);
            this->datasize = test.datasize;
        }
        Test(Test&& test)
        {
            printf("r copy construct\n");
            // 自己实现真正的移动
            this->buffer = test.buffer;
            this->datasize = test.datasize;
            test.buffer = nullptr;
            test.datasize = 0;
        }
        ~Test()
        {
            if (nullptr != buffer)
            {
                delete[] buffer;
                buffer = nullptr;
            }
            datasize = 0;
        }
    private :
        char* buffer;
        int datasize;
};

int main(int argc, char* argv[])
{
    Test test;

    // 调用普通的拷贝构造函数
    Test test1(test);

    // std::move 只是告诉编译器,让其调用移动构造函数,真正的移动需要RD自己实现
    Test test2(std::move(test));

    return 0;
}

以上代码可以在gcc482以上,使用g++ main.cpp -std=c++11 -g 编译通过

3、完美转发std::forward

当我们用一个变量接收右值引用时,根据C++ 标准的定义,这个变量变成了一个左值。那么他永远不会调用接下来函数的右值版本,这可能在一些情况下造成拷贝。
为了解决这个问题 C++ 11引入了完美转发,支持右值判断的推导,若原来是一个右值,那么他转出来就是一个右值,否则为一个左值。

#include <string.h>
#include <iostream>

class Test
{
    public:
        Test()
        {   
            buffer = new char[1024];
            datasize = 1024;
        }   
        Test(const Test& test)
        {   
            // 调用深拷贝
            printf("l copy construct\n");
            this->buffer = new char[test.datasize];
            memcpy(this->buffer, test.buffer, test.datasize);
            this->datasize = test.datasize;
        }   
        Test(Test&& test)
        {   
            printf("r copy construct\n");
            // 实现真正的移动
            this->buffer = test.buffer;
            this->datasize = test.datasize;
            test.buffer = nullptr;
            test.datasize = 0;
        }   
        ~Test()
        {   
            if (nullptr != buffer)
            {   
                delete[] buffer;
                buffer = nullptr;
            }   
            datasize = 0;
        }   
    private :
        char* buffer;
        int datasize;
};

int main(int argc, char* argv[])
{
    Test test;

    // 只是强转为r reference,没做任何其他事
    Test&& test1 = std::move(test);

    // 由于**test1这个右值引用本身是左值**,此处会调用拷贝构造
    Test test2(test1);

    // forward支持对test1类型推导,test1为右值引用,会转成右值,调用移动构造函数
    Test test3(std::forward<Test>(test1));
    return 0;
}

总结

  • std::move执行到右值的无条件转换。就其本身而言,它没有move任何东西。
  • std::forward只有在它的参数绑定到一个右值上的时候,它才转换它的参数到一个右值。
  • std::move和std::forward在运行期都没有做任何事情。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值