c++11 右值引用

最近看了祁宇大哥的深入应用c++11中的用c++11提高程序性能部分,对右值引用做一个小读后感悟及总结,其实右值引用没想象的那么神秘:

c++11 增加了一个新的类型,右值引用,标记为T&&。c++11中所有的值必属于左值、将亡值、纯右值,其中将亡值和纯右值属于右值,比如,非引用返回的临时变量、运算表达式产生的临时变量、原始字面量和lambda表达式等都是纯右值,将要被移动的对象、T&&函数返回值、std::move返回值和转换为T&&的类型的转换函数的返回值属于将亡值。


右值引用对程序性能的改进:
struct A
{
    A()
    {

    }
    A(const A& a)
    {

    }
    ~A()
    {

    }
};

A GetA()
{
    return A();
}

int main()
{
    A a = GetA(); //函数的返回结果对象需要调用拷贝构造函数拷贝给a,然后返回结果对象析构掉
    return 0;
}

int main()
{
    A&& a = GetA();//函数返回结果对象不用在拷贝,直接转移给a,减少了一次拷贝构造和析构的调用开销
    return 0;
}

T&& 类型的变量并不一定是左值,应为T未定是如函数模板的类型自动推导或auto关键字时,T&&是一个未定义类型(universal reference),这需要应用c++11的折叠规则:
1)所有的右值应用折叠刀右值应用上还是一个右值引用。
2)所有的其他引用类型之间的叠加都将变成左值引用。
如:
int w1, w2;
auto&& v1 = w1;// v1 是一个左值,auto推导的是一个左值类型。左值类型+右值类型=左值类型。
decltype(w1)&& v2 = w2;//将一个左值付给一个右值类型是不合法的
需要用move语义将左值转换为右值,如下:
decltype(w1)&& v2 = std::move(w2);
move语义的唯一作用就是将一个左值转换为一个右值,使我们可以通过右值引用使用该值,实现移动构造,它实际上并不移动任何东西。
如果有一个很大的容器list:
std::list<std::string> tokens;
//初始化tokens
std::list<std::string> t = tokens; //需要大量的拷贝

std::list<std::string> tokens;
std::list<std::string> t = std::move(tokens); //move将左值转换为了右值,然后就会调用右值参数的赋值靠别函数转换资源的所有权,避免了深拷贝。

下面是一个避免深拷贝的例子:
class MyString
{
    private:
        char *m_data;
        size_t m_len;
        void copy_data(constchar *s)
        {
            m_data = newchar[m_len+12];
            memcpy(m_data, s, m_len);
            m_data[_len] = '\0';
        }

        public:
            MyString()
            {
                m_data = NULL;
                m_len = 0;
            }
            MyString(const char *p)
            {
                m_len = strlen(p);
                copy_data(p);
            }

            MyString(const MyString&str)
            {
                m_len = str.m_len;
                copy_data(str.m_data);
            }  

            MyString& operator=(const MyString&str)
            {
                if(this != $str)
                {
                    m_len = str.m_len;
                    copy_data(str._data);
                }
                return *this;
            }

            virtual ~MyString()
            {
                if(m_data) delete []m_data;
            }
 
            MyString(MyString&& str)
            {
                _len = str.len;
                _data = str._data;
                str._len = 0;
                str._data = NULL;
            }
            MyString& operator=(MyString&& str)
            {
               if(this != &str)
               {
                _len = str._len;
                _data = str._data;
                str._len = 0;
                str._data = NULL:
               }
               return *this;
            }
};

如果调用拷贝构造或赋值拷贝函数是,用move将左值转换为右值就会调用右值参数的拷贝构造和赋值拷贝函数,从而避免了深拷贝,现在明白了移动语义的含义了吧,实际上就c++11增减了个新类型,然后重载对象的拷贝构造和赋值拷贝函数,在函数中将内存地址转移给另一个指针对象,将原来的指针对象付为NULL,move作用就是将一个左值转为右值一遍调用右值参数的函数。所以移动语义中的权限转移实际上就是堆内存地址的转移。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值