C++11新特性之右值引用、移动构造、移动赋值、移动迭代器

1、左值:可寻址的、引用的是某一个对象、可位于赋值运算符的左边、可以被赋值。

2、右值:可读的、引用的是某一个对象指向的地址中的数据、通常位于赋值运算符的右边、取出值赋给其他变量。

3、右值引用(T &&)

           右值引用就是必须绑定到右值的引用,通过&&来获得右值引用;

           声明一个右值引用:int &&a = 0

       说明:

            a、右值引用所引用的临时对象可以在该临时对象被初始化之后再次修改(这是为了允许move语义),即在右值引用被初始化后,可以使用左值或者左值引用改变右值引用所引用的临时对象的值。
            b、能使用右值引用初始化给左值引用(即左值引用绑定到右值引用指向的对象),不能用左值或者左值引用初始化右值引用。

            c、C++11使用move函数,用来获取绑定到左值或者左值引用上的右值引用。(需包含头文件utility)。

            d、右值引用可以防止发生不必要的拷贝。(C++03中深拷贝会隐式的发生在值传递时期)     

int a = 1;
//int &a = 1; //error, const int &a = 1 ok

//左值,左值引用,右值引用,初始化,赋值
int &aa = a;

//int &&aaa = a;//error,不能使用左值初始化右值引用
//int &&aaa = aa;//error,不能使用左值引用初始化右值引用

int &&aaa1 = std::move(a);//ok
int &&aaa2 = std::move(aa);//ok

std::cout << "a:" << a << std::endl; // 输出:a:1
std::cout << "&aaa1:" << &aaa1 << std::endl;// 输出:&aaa1:00D3DAE8
std::cout << "&aaa2:" << &aaa2 << std::endl;// 输出:&aaa2:00D3DAE8

int &&aaa = 0;
aaa = a;//ok, 可以使用左值改变右值引用指向对象的值。
aaa = aa;//ok, 可以使用左值引用改变右值引用指向对象的值。

int &&bbb = 1;
int b = bbb;//ok, 可以使用右值引用初始化左值
int &bb = bbb;//ok, 可以使用右值引用初始化左值引用

   

4、移动构造函数和移动赋值函数

            移动构造函数的参数和拷贝构造函数不同,拷贝构造函数的参数是一个左值引用,但是移动构造函数的参数是一个右值引用。这意味着,移动构造函数的参数是一个右值或者将亡值的引用。也就是说,只有用一个右值,或者将亡值初始化另一个对象的时候才会调用移动构造函数。而move语句,就是将一个左值变成一个将亡值。

            移动赋值函数的参数和普通赋值函数不同,移动赋值函数的参数是一个右值引用。

       说明:

                 拷贝构造函数的调用时机:形实结合、函数返回值、使用一个对象出初始化另一个对象。

                 移动构造函数的调用时机:使用右值或者将亡值(对左值或者左值引用使用move函数取得将亡值)初始化另一个对象。

                 移动赋值函数的调用时机:使用右值或者将亡值赋值给另一个对象。

                 移动构造函数通常是noexcept。

#include "stdafx.h"
#include <iostream>
#include <utility>
#include <vector>
#include <cstring>
#include <cstdlib>

class CString{
public:
    //普通构造函数
    CString(char value[])
    {
        std::cout << "...普通构造函数..." << std::endl;
        str = NULL;
        int len = strlen(value);
        str = (char *)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, value);
    }
    //拷贝构造函数
    CString(const CString &rhs)
    {
        std::cout << "...拷贝构造函数..." << std::endl;
        str = NULL;
        int len = strlen(rhs.str);
        str = (char *)malloc(len + 1);
        memset(str, 0, len + 1);
        strcpy(str, rhs.str);
    }
    //移动构造函数
    CString(CString &&rhs)
    {
        std::cout << "...移动构造函数..." << std::endl;
        str = NULL;
        str = rhs.str;
        rhs.str = NULL;
    }
    //移动赋值函数
    const CString& operator=(Str &&s)
	{
		std::cout << "移动赋值函数..." << std::endl;
		if (str != NULL) {
			free(str);
			str = NULL;
		}
		str = s.str;
		s.str = NULL;
		return *this;
	}
    //析构函数
    ~CString()
    {
        std::cout << "...析构函数..." << std::endl;
        if (str  != NULL)
        {
            free(str);
            str = NULL;
        }
    }
private:
    char *str;
};

int main()
{
    char strValue[] = "test";
    CString str(value);// 调用普通构造函数

	CString s1(strValue);
	CString s2;	//调用默认构造函数
	s2 = std::move(s1);//调用移动赋值函数
    
    std::vector<CString> vecStr1;
    vecStr1.push_back(str);//调用拷贝构造函数
    std::cout << vecStr1[0].str << std::endl;
    if (str.str != NULL){
        std::cout << str.str << std::endl;//运行会打印
    }

    std::vector<CString> vecStr2;
    vecStr2.push_back(std::move(str));//移动构造函数(传递一个右值引用)
    std::cout << vecStr2[0].str << std::endl;
    if (str.str != NULL){
        std::cout << str.str << std::endl;//运行不会打印
    }
}

5、移动迭代器

          C++11中可以使用make_move_iterator函数将一个普通的迭代器转换成移动迭代器(可避免拷贝操作提升性能)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
右值引用和move语义是C++ 11中重要的特性之一,可以提高程序的效率和性能。右值引用是一种新的引用类型,其绑定到临时对象或将要销毁的对象上,而不是左值对象。move语义则是利用右值引用,将一个对象的资源所有权从一个对象转移到另一个对象,避免了不必要的内存拷贝,提高了程序的效率。 下面是一个使用右值引用和move语义的例子: ```c++ #include <iostream> #include <vector> using namespace std; vector<int> getVector() { vector<int> v = {1, 2, 3, 4}; return v; } int main() { vector<int> v1 = getVector(); // 拷贝构造函数 vector<int> v2 = move(v1); // 移动构造函数 cout << "v1 size: " << v1.size() << endl; // 输出 0 cout << "v2 size: " << v2.size() << endl; // 输出 4 return 0; } ``` 在上面的例子中,getVector函数返回一个临时对象vector<int>,该临时对象是一个右值。在主函数中,我们使用拷贝构造函数将临时对象的值拷贝到v1中,然后使用move函数将v1中的值移动到v2中。由于move函数使用了右值引用,将v1中的资源所有权转移到了v2中,避免了不必要的内存拷贝,提高了程序的效率。最后,我们输出v1和v2的大小,可以看到v1的大小为0,v2的大小为4,说明资源已经成功转移。 需要注意的是,使用move语义之后,原对象的值会被移动到新对象中,并且原对象的值会被置为默认值(例如,对于vector而言,原对象的大小为0)。如果需要保留原对象的值,则需要在移动之前先进行一次拷贝操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值