IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++11移动语义解析 -> 正文阅读

[C++知识库]C++11移动语义解析

当给函数传递对象当做函数参数时,可以使用引用类型来减少拷贝对象的代价,尤其是避免容器的拷贝等。?但是当把函数内的局部对象当做返回值时,我们无法返回该局部对象的引用,导致每次返回局部对象都会进行拷贝。?因为返回局部对象的引用是无意义的,当函数调用完成,局部对象就被析构,所以其引用指向了一块析构的内存。程序如果使用移动操作,避免了拷贝,将新变量指向了局部变量的内容。例如:

std::vector<int> GetNums() {
? std::vector<int> nums;
? nums.push_back(1);
? nums.push_back(2);
? return nums;
}


std::vector<int> result = GetNums(); ?// 调用vector的移动构造函数,避免了拷贝。
标准库的容器vector,string等实现了拷贝语义,所以这些容器作为函数的局部对象时都可以直接返回。
?

C++11提供了移动语义,分别是移动构造函数和移动赋值运算符,那么什么时候会触发移动语义?

当右值引用被当做初始值或者赋值操作的右侧运算对象时,程序将使用移动操作。

1. 对于移动构造函数两种情况会触发移动语义:函数返回把临时对象当做返回值,使用std::move。

2. 对于移动赋值运算符三种情况会触发移动语义:函数返回把临时对象当做返回值,使用std::move, 临时对象。

以以下代码为例:


#include <string.h> 
#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <map>
#include <utility>
#include <functional>
#include <algorithm>
#include <cassert>
 
class Student {
public:
  Student() {
    id_ = 0;
    name_ = nullptr;
  }
 
  Student(int id, const char* name) {
    std::cout << "Constructor" << std::endl;
    id_ = id;
    size_t len = strlen(name);
    name_ = new char[len + 1];
    strcpy(name_, name);
  }
 

  ~Student() {
    std::cout << "De-constructor" << std::endl;
    id_ = 0;
    if (name_ != nullptr) {
      delete[] name_;
      name_ = nullptr;
    }
  }
 
  Student(const Student& student) {
    std::cout << "Copy Constructor" << std::endl;
 
    id_ = student.id_;
 

    size_t len = strlen(student.name_);
    name_ = new char[len + 1];
    strcpy(name_, student.name_);
  }
 
  Student(Student&& student) {
    std::cout << "Move Constructor" << std::endl;
     id_ = student.id_;
     name_ = student.name_;
 
    student.id_ = 0;
    student.name_ = nullptr;
  }
 
  Student& operator=(const Student& student) {
    std::cout << "Copy Assignment" << std::endl;
 
    if (this == &student) {
      return *this;
    }
 
    id_ = student.id_;
 
    size_t len = strlen(student.name_);
    name_ = new char[len + 1];
    strcpy(name_, student.name_);
 
    return *this;
  }
 
  Student& operator=(Student&& student) {
    std::cout << "Move Assignment" << std::endl;
 
    if (this == &student) {
      return *this;
    }
    if (name_ != nullptr) {
      delete[] name_;
    }
 
    id_ = student.id_;
    name_ = student.name_;
 
    student.id_ = 0;
    student.name_ = nullptr;
 
    return *this;
  }
 
  void Print() {
    std::cout << id_ << " : " << (name_ == nullptr ? "NULL": name_) << std::endl;
  }
 
private:
  int id_;
  char* name_;
};
 
void PrintStudent(Student student) {
  student.Print();
}
 
Student GetStudent() {
  printf("get student\r\n");
  Student student(123, "123");
  return student;
}
 
int main() {
  Student a(1, "1");
  std::cout << "====================================" << std::endl;
 
  PrintStudent(a);  
  //copy constructor : 按值传递形参,需要将a拷贝到一个临时对象‘tempA’
  //de-con :tempA析构
  std::cout << "================1====================" << std::endl;
 
  PrintStudent(Student(2, "2"));  
  //con:(2,'2')构建一个临时对象作为形参传递给PrintStudent(引用方式)
  //de-con:临时对象析构
  std::cout << "================2====================" << std::endl;
 
  PrintStudent(std::move(Student(2, "2")));  
  //con: (2,"2")构建一个临时对象A(左值)
  //move con:将临时对象A move成右值引用对象B
  //de-con: 临时对象A析构
  //de-con:临时对象B析构
  std::cout << "================3====================" << std::endl;
 
  PrintStudent(std::move(a));  
  a.Print();  
  //move con:将对象a move成右值引用对象b
  //de-con: 对象b析构
  std::cout << "================4====================" << std::endl;
 
  Student a2 = GetStudent(); 
  //con:当函数返回值为对象时,返回临时对象的引用,相当于直接构造新对象避免了拷贝
  std::cout << "================5====================" << std::endl;
 
  Student a3;
  a3 = Student(3, "3");  
  //con:构造临时对象
  //move assign:将临时对象copy给a3, 此时用的是move assign
  //de-con: 临时对象析构
  std::cout << "================6====================" << std::endl;
 
  Student a4(4, "4");
  a3 = a4;  
  //con:构造对象a4
  //copy assign: 对象a4赋值给a3, 此时用的是copy assign
  std::cout << "================7====================" << std::endl;
 
  a3 = std::move(a4);  
  //move assign : 将对象a4 move成右值引用对象3,此时用的是move assign
  std::cout << "================8====================" << std::endl;
 
  a3 = GetStudent();  

  //con : 构造对象student
  //move assign: student对象赋值给a3, 此时用的是move assign
  //de-con: student对象析构
  std::cout << "================9====================" << std::endl;
 
  return 0;
}

参考文章:

C++11右值引用(一看即懂)??????c++ 之 std::move 原理实现与用法总结_学之知之的博客-CSDN博客_std::move

C++11的移动语义_博客-CSDN博客

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:04:24  更:2022-03-16 22:06:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:34:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码