当前位置: 首页 > news >正文

23.C++11(三)

一.右值不能直接取地址(前情回顾)

#include <iostream>
#include <string.h>using namespace std;void x(int&& x1)
{printf("%p\n",&x1);
}int main()
{x(1);x(100);// printf("%p\n",&1);// printf("%p\n",&x100);return 0;
}

传参之后,x1本身是左值,可以取地址,要加上move(x1)才能变成右值

本节比较重要,建议看完上面的在开始继续学习:

https://blog.csdn.net/weixin_60668256/article/details/153720945?fromshare=blogdetail&sharetype=blogdetail&sharerId=153720945&sharerefer=PC&sharesource=weixin_60668256&sharefrom=from_link

二.完美转发

1.万能引用

上次我们讲到,右值被引用传参之后,会变成左值

但是难道每一次模板都要写两个吗?(一个左值,一个右值)

包括const &&  --->  const &&           const &    ----->  const &

测试如下:

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }// 引用
// 传左值->左值引用
// 传右值->右值引用
template<typename T>
void PerfectForward(T&& t)
{// 模版实例化是左值引用,保持属性直接传参给Fun// 模版实例化是右值引用,右值引用属性会退化成左值,转换成右值属性再传参给FunFun(forward<T>(t));
}int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);			  // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

所以我们通过Fun函数进行识别

这里本质上就是编译器帮我们识别出来了四个版本的函数,如下:

void PerfectForward(int& t)
{Fun(t);
}void PerfectForward(int&& t)
{Fun(move(t));
}void PerfectForward(const int& t)
{Fun(t);
}void PerfectForward(const int&& t)
{Fun(move(t));
}

这时候,就有了完美转发:

这样就实现了我们上面那四个函数的功能了

2.完美转发forward()

#include <iostream>
#include <utility> // 包含std::forward// 被转发的目标函数:重载左值和右值版本
void target(int& x)  { std::cout << "左值引用版本\n"; }
void target(int&& x) { std::cout << "右值引用版本\n"; }// 完美转发的模板函数
template <typename T>
void forwarder(T&& t) {target(std::forward<T>(t)); // 用std::forward还原原始值类别
}int main() {int a = 10;forwarder(a);   // 传入左值,调用左值版本的targetforwarder(20);  // 传入右值,调用右值版本的targetreturn 0;
}

3.move()和forward()的差别

4.forward()和万能引用

三.新的类功能

1.默认成员函数

原来是6个默认的成员函数,这里又多了两个(移动构造函数和移动赋值运算符重载)

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}private:string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);return 0;
}

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}// 自动生成拷贝构造和移动构造~Person(){}
private:string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);return 0;
}

s1的资源给了s3,s1自己就没资源了

默认的移动构造是给自身没有资源需要管理,但是自定义类型有资源需要进行管理的类型进行的

移动赋值也是同理:

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}//Person(Person&& p) = default;//Person& operator=(Person && p) = default;//Person(const Person& p) = default;//Person& operator=(const Person& p) = default;// 自动生成拷贝构造和移动构造// ~Person()// {}
private:string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);Person s4;s4 = std::move(s2);return 0;
}

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}//Person(Person&& p) = default;//Person& operator=(Person && p) = default;//Person(const Person& p) = default;//Person& operator=(const Person& p) = default;// 自动生成拷贝构造和移动构造~Person(){}
private:string _name;int _age;
};int main()
{Person s1;Person s2 = s1;Person s3 = std::move(s1);Person s4;s4 = std::move(s2);return 0;
}

2.类成员变量初始化

3.强制生成默认函数的关键字default:

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}Person(Person&& p) = default;Person& operator=(Person && p) = default;Person(const Person& p) = default;Person& operator=(const Person& p) = default;// 自动生成拷贝构造和移动构造~Person(){}
private:string _name;int _age;
};

这里显示让Person进行实现移动构造和赋值,但是这里必须是要求要四个一起写

4.delete关键字

和上面的default类似:

如果我们有一个类不想让别人进行拷贝:

class Person
{
public:Person(const char* name = "111111111111", int age = 0):_name(name), _age(age){}//C++11Person(const Person& p) = delete;Person& operator=(const Person & p) = delete;// 只声明不实现,声明为私有// C++98
//private:
//	Person(const Person& p);
//	Person& operator=(const Person & p);Person(const Person& p) = delete;Person& operator=(const Person& p) = delete;
private:string _name;int _age;
};

5.final关键字

6.override关键字

7.explicit关键字

修饰函数

8.#pragma pack()

四.可变参数模板(我们目前不常用,较麻烦)

// 可变模版参数
// 参数类型可变
// 参数个数可变
// 打印参数包内容
template <class ...Args>
void ShowList(Args... args)
{// 可变参数模版编译时解析// 下面是运行获取和解析,所以不支持这样用cout << sizeof...(args) << endl;for (size_t i = 0; i < sizeof...(args); i++){cout << args[i] << " ";}cout << endl;
}int main()
{ShowList();ShowList(1);ShowList(1, "xxxxx");ShowList(1, "xxxxx", 2.2);return 0;
}

void Print()
{cout << endl;
}template <class T, class ...Args>
void Print(T&& x, Args&&... args)
{cout << x << " ";Print(args...);
}// 编译时递归推导解析参数
template <class ...Args>
void ShowList(Args&&... args)
{Print(args...);
}int main()
{ShowList();ShowList(1);ShowList(1, "xxxxx");ShowList(1, "xxxxx", 2.2);return 0;
}

底层实现类似于下面:

void Print()
{cout << endl;
}template <class T, class ...Args>
void Print(T&& x, Args&&... args)
{cout << x << " ";Print(args...);
}// 编译器推导的
void Print(double x)
{cout << x << " ";Print();
}void Print(const char* x, double z)
{cout << x << " ";Print(z);
}void Print(int x, const char* y, double z)
{cout << x << " ";Print(y, z);
}// 编译时递归推导解析参数
template <class ...Args>
void ShowList(Args&&... args)
{Print(args...);
}
// 编译器实例化生成
void ShowList(int x, const char* y, double z)
{Print(x, y, z);
}int main()
{ShowList(1, "xxxxx", 2.2);return 0;
}

还要其他的遍历方式:

template <class T>
int PrintArg(T t)
{cout << t << " ";return 0;
}template <class ...Args>
void ShowList(Args... args)
{int arr[] = { PrintArg(args)... };cout << endl;
}// 编译推演生成下面的函数
// void ShowList(int x, char y, std::string z)
// {
// 	int arr[] = { PrintArg(x),PrintArg(y),PrintArg(z) };
// 	cout << endl;
// }int main()
{//ShowList(1);//ShowList(1, 'A');ShowList(1, 'A', std::string("sort"));return 0;
}

还可以这么写:

template <class ...Args>
void ShowList(Args... args)
{int arr[] = { (cout<<(args)<<" ", 0)...};cout << endl;
}void ShowList(int x, char y, std::string z)
{int arr[] = { (cout<<(x)<<" ", 0), (cout << (y) << " ", 0), (cout << (z) << " ", 0) };cout << endl;
}int main()
{ShowList(1, 'A', std::string("sort"));return 0;
}

auto推导数组(退化成 int* ):

#include <iostream>using namespace std;int main() {int arr[3] = {1, 2, 3};auto x = arr; // x 推导为 int*(数组名退化)// for(auto e:x)// {// 	cout << e << " ";// }// cout << endl;std::cout << typeid(x).name() << std::endl; // 输出:int*(因编译器而异)x[0] = 10; // 可通过指针访问数组元素x[1] = 11;std::cout << arr[0] << std::endl; // 输出 10std::cout << arr[1] << std::endl; // 输出 11return 0;
}

五.emplace_back的实现

1.emplace_back()的使用

2.emplace_back()的实现

emplace_back()是一次传递多个值吗?

template<class... Args>ListNode(Args&&... args):_next(nullptr), _prev(nullptr), _data(move(args...)){}

list内部,我们要实现一下这个函数

template <class... Args>void emplace_back(Args&&... args){insert(end(),args...);}template <class... Args>iterator insert(iterator pos,Args&&... args){Node* cur = pos._node;Node* newnode = new Node(args...);Node* prev = cur->_prev;// prev  newnode  curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}

但是这里还是不太对,我们看到第二个还是我们的深拷贝

这里就涉及到了我们的,传参会导致参数变成左值,这里就涉及到我们的完美转发了

template<class... Args>ListNode(Args&&... args):_next(nullptr), _prev(nullptr), _data(forward<Args>(args)...){}
template <class... Args>void emplace_back(Args&&... args){insert(end(),forward<Args>(args)...);}template <class... Args>iterator insert(iterator pos,Args&&... args){Node* cur = pos._node;Node* newnode = new Node(forward<Args>(args)...);Node* prev = cur->_prev;// prev  newnode  curprev->_next = newnode;newnode->_prev = prev;newnode->_next = cur;cur->_prev = newnode;return iterator(newnode);}

这样就对了

3.可变模板参数的意义是啥?

4.push_back和emplace_back的区别

http://www.dtcms.com/a/517579.html

相关文章:

  • 梅州市五华县建设银行网站景观设计公司起名
  • 刚做淘客没有网站奥门网站建设
  • 专业做网站机构哪些ppt网站是免费的
  • 爱情动做网站推荐wordpress去除更新
  • 深圳技术支持 骏域网站建设wordpress 导出pdf文件
  • 深圳公明网站建设问题不大工作室 网站
  • Langchain从零开始到应用落地案例[AI智能助手]【1】---调用ollama模型实现简单循环会话
  • 【架构】MVP 对比 MVVM
  • 建立网站的基本流程有哪些步骤给wordpress添加小图标
  • Springboot——整合Aspose实现table的字段填充与表格复制
  • 产品展示型网站赏析河南网站建设电话
  • 国外免费搭建网站源码企业网站建设策划书 前言
  • 【网络代理相关知识】
  • 美股及墨西哥股票数据接口文档
  • 做电销哪些网站可以找到客户做网站的北京
  • 网站描述修改做h5那个网站好
  • 什么公司时候做网站厦门编程培训机构
  • 建设网站 买了域名还要什么网站权重分为几个等级
  • 操作系统 进程(3)进程调度算法
  • 建筑设计自学网站做一个平台网站要多少钱
  • 专门做单页的网站把网站制作成app
  • 电子商务网站建设实践报告摘要如何做查询网站
  • HX711电子秤模块详解(STM32)
  • 成都高速公路网站建设招标消防工程师证怎么考
  • 白山北京网站建设大连甘井子区教育公共服务平台
  • SpringBoot考勤管理系统
  • 公司网站站群是什么为什么要建设就业指导网站
  • 用cosyvoice批量把生成有声书
  • 三门峡企业网站建设公司全球最大的c2c平台
  • AAAI 2025 | 即插即用,川大Mesorch刷新SOTA,用「介观」Transformer架构终结图像造假