右值引用和移动构造函数

右值引用

C++11 中的一个新特性,用于实现移动语义和完美转发。右值引用用 `&&` 表示,可以绑定到临时对象或将要被销毁的对象,是一种可修改的引用类型。

右值引用的主要作用有两个:

1. 实现移动语义:右值引用可以将资源所有权从一个对象转移到另一个对象,避免了不必要的内存分配和复制,提高了程序的性能和效率。

2. 实现完美转发:右值引用可以将参数按照原始类型精确地转发到下一层函数,避免了类型退化和多余的拷贝构造函数调用,提高了程序的灵活性和可维护性。

以下是一个简单的右值引用的例子,用于实现移动语义:

```cpp

#include <iostream>
#include <vector>

class MyVector {
public:
    MyVector() {
        std::cout << "Default constructor" << std::endl;
    }

    MyVector(const MyVector& other) {
        std::cout << "Copy constructor" << std::endl;
    }

    MyVector(MyVector&& other) {
        std::cout << "Move constructor" << std::endl;
    }

    ~MyVector() {
        std::cout << "Destructor" << std::endl;
    }
};

MyVector createVector() {
    MyVector v;
    return v; // 返回一个临时对象
}

int main() {
    std::vector<MyVector> vec;

    vec.push_back(MyVector()); // 调用默认构造函数和移动构造函数

    MyVector v = createVector(); // 调用默认构造函数和移动构造函数

    return 0;
}


```

在上面的代码中,我们定义了一个 `MyVector` 类,用于演示移动语义。在类中,我们定义了默认构造函数、拷贝构造函数和移动构造函数,并在每个构造函数中输出一条提示信息。在 `createVector` 函数中,我们创建了一个临时对象并返回。在 `main` 函数中,我们创建了一个 `std::vector` 容器,并向其中添加一个临时对象和一个从 `createVector` 函数中返回的对象。在程序运行时,我们可以看到输出的提示信息,其中有两次移动构造函数的调用,分别对应于临时对象和从 `createVector` 函数中返回的对象的转移。

通过使用右值引用,我们可以实现移动语义,避免了不必要的拷贝构造函数调用,提高了程序的性能和效率。

移动构造函数

移动构造函数是 C++11 中的一个新特性,用于实现移动语义。移动构造函数的作用是将一个对象的资源(如内存、文件句柄、网络连接等)所有权从一个对象转移到另一个对象,避免了不必要的内存分配和复制,提高了程序的性能和效率。

移动构造函数的特点有:

1. 接受一个右值引用作为参数,表示将要被移动的对象。

2. 将被移动对象的资源所有权转移到新对象中,使用移动语义。

3. 将被移动对象的指针置为 `nullptr`,避免重复释放。

以下是一个简单的移动构造函数的例子,用于演示移动语义:

```cpp

#include <iostream>

class MyString {
public:
    MyString() {
        std::cout << "Default constructor" << std::endl;
        data_ = nullptr;
        size_ = 0;
    }

    MyString(const char* str) {
        std::cout << "Constructor with const char*" << std::endl;
        size_ = std::strlen(str);
        data_ = new char[size_ + 1];
        std::strcpy(data_, str);
    }

    MyString(const MyString& other) {
        std::cout << "Copy constructor" << std::endl;
        size_ = other.size_;
        data_ = new char[size_ + 1];
        std::strcpy(data_, other.data_);
    }

    MyString(MyString&& other) {
        std::cout << "Move constructor" << std::endl;
        size_ = other.size_;
        data_ = other.data_;
        other.size_ = 0;
        other.data_ = nullptr;
    }

    ~MyString() {
        std::cout << "Destructor" << std::endl;
        delete[] data_;
    }

private:
    char* data_;
    size_t size_;
};

MyString createString() {
    MyString s("Hello, world!");
    return s; // 返回一个临时对象
}

int main() {
    MyString s1("Hello, world!"); // 调用构造函数
    MyString s2(s1); // 调用拷贝构造函数
    MyString s3(std::move(s1)); // 调用移动构造函数

    MyString s4 = createString(); // 调用移动构造函数

    return 0;
}


```

在上面的代码中,我们定义了一个 `MyString` 类,用于演示移动构造函数。在类中,我们定义了默认构造函数、构造函数(接受 `const char*` 类型的参数)、拷贝构造函数和移动构造函数,并在每个构造函数和析构函数中输出一条提示信息。在 `createString` 函数中,我们创建了一个临时对象并返回。在 `main` 函数中,我们创建了四个 `MyString` 对象,分别调用了默认构造函数、构造函数、拷贝构造函数和移动构造函数,以及从 `createString` 函数中返回的对象的移动构造函数。在程序运行时,我们可以看到输出的提示信息,其中有三次构造函数的调用和两次移动构造函数的调用,分别对应于对象的创建和转移。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值