C++11新特性(一):语言特性
C++11新特性
总结C++11特性时发现整个内容角度,建议查看前先查看目录。
语言特性
右值引用
右值的分类为将亡值和字面量。将亡值就是将要销毁的对象以及临时的变量,字面量就是常量。左值就是变量。
右值引用,通常使用&&表示。
// 字面量
int a = 1; // a变量,左值;b变量,右值
int Func(int a, int b){
return a + b;
}
int res = Func(1, 2); // 此时Func(1, 2)返回的就是一个临时变量,即是右值。res变量是一个左值,\
延长了Func(1, 2)右值的生命周期。
int& b = a; // 左值引用
int&& c = a; // 右值引用
移动语义
移动语义指的是将一个对象的资源所有权转发给另一个对象。常用于类的移动构造函数和移动赋值运算符。
只要类中有任何构造函数,就不会生成默认构造函数
int a = 1;
int res = Func(1, 2);
int&& b = move(a); // move用来实现左值到右值转变
int&& c = move(a); // std::move
class MyClass{
public:
MyClass() = default; // 默认构造函数
MyClass(MyClass& obj){ // 拷贝构造函数
cout << "left value" << endl;
}
MyClass(MyClass&& obj){ // 移动构造函数
cout << "right value" << endl;
}
~MyClass(){}
};
int main()
{
MyClass a;
MyClass b(a); // left value
MyClass&& xs = move(a); // 右值
MyClass c(xs); // left value,此时为输出left value的原因是因为本身右值引用也是一个变量,\
所以在调用构造函数时,会调用拷贝构造函数
MyClass d(move(xs)); // 使用move直接转变为右值才会调用移动构造函数
}
通常拷贝构造函数实现的是对象的浅拷贝,浅拷贝指的是将两个对象的指针指向同一块资源。深拷贝指的是直接复制一份资源给新的对象。
浅拷贝的缺点是当旧对象析构时,会将资源一起释放掉,而新对象指针此时还指向被释放掉的资源,那么新对象进行释放的时候,就会发生double free这种重复释放问题。
移动语义的好处是,既不用像深拷贝一样复制一份资源而是将新对象指针指向旧对象指向的资源,然后将旧指针置为空即可。

移动语义实现:
class MyClass{
private:
int* data
public:
MyClass() = default; // 默认构造函数
#if 0
MyClass(MyClass& obj){ // 拷贝构造函数,浅拷贝
cout << "left value" << endl;
data = obj.data; // 只复制指针的值
}
#else
MyClass(MyClass& obj){ // 拷贝构造函数,深拷贝
cout << "left value" << endl;
data = new int(*obj.data); // 分配内存、赋值为就对象的资源并返回一个指针给data
}
#endif
MyClass(MyClass&& obj){ // 移动构造函数,移动语义实现
this.data = obj.data;
obj.data = nullptr;
}
~MyClass(){}
};
转发引用
转发引用的实现由T&&或者auto&&实现,T是一个模板参数。这能够用于实现完美转发,即传递参数的同时还能保证其值的类型(左值就是左值,暂时对象、变量传递作为右值)。如下代码,如果我们直接将右值传到构造函数中,那么构造函数会认为此右值变量是一个左值,从而调用拷贝构造函数,并不会调用移动构造函数。
class MyClass{
public:
MyClass() = default; // 默认构造函数
MyClass(MyClass& obj){ // 拷贝构造函数
cout << "left value" << endl;
}
MyClass(MyClass&& obj){ // 移动构造函数
cout << "right value" << endl;
}
~MyClass(){}
};
int main()
{
MyClass a;
MyClass b(a); // left value
MyClass&& xs = move(a); // 右值
MyClass c(xs); // left value,此时为输出left value的原因是因为本身右值引用也是一个变量,\
所以在调用构造函数时,会调用拷贝构造函数
MyClass d(move(xs)); // 此时必须使用move直接转变为右值才能调用移动构造函数
}
当我们引入T&&就可以解决这个问题,此时会直接根据参数的类型自动推导类型。
T& &-->T&T& &&-->T&T&& &-->T&T&& &&-->T&&
int a = 0; // int : 左值
auto&& b = a; // int& : 左值
auto&& c = 0; // int&& :右值
接下来我们可以借用T&&和auto&&来实现完美转发。注意完美转发解决的问题是参数传递时类型会发生转换的问题。
template<typename T>
void Func(T&){
cout << "left value" << endl;
}
template<typename T>
void Func(T&&){
cout << "right value" << endl;
}
int a = 0;
auto&& b = a;
auto&& c = 0;
Func(1); // 1 call Func(int&&)
Func(a); // a call Func(int&)
Func(c); // c vall Func(int&), 右值引用直接作为传递会发生退化,退化为左值,因为右值本身就是一个变量
Func(move(a)); // call Func(int&&)
// 完美转发:使用std::forward<T>(arg)实现
template<typename T>
void makeResource(T&& arg) {
Func(forward<T>(arg));
}
makeResource<int>(c); // 此时传递右值引用到参数,forward就会保证参数的类型不变进行传递,从而调用Func(T&&)
可变参数模板
...语义创建一个参数包或者扩展参数包,模板参数包接受0或多个模板参数。有至少一个参数包的模板叫做可变参数模板。
template<typename... T>
void Func(){
cout << "nihao";
}
#include <numeric>
template<typename T1, typename... Args>
auto Sum(T1 first, Args... args) -> decltype(first)
{
auto values = {first, args...}; // ...扩展参数包
return accumulate(values.begin(), values.end(), first);
}
cout << Sum(1, 22, 33, 66) << endl;
列表初始化
列表初始化,就是使用花括号进行初始化。{1, 2, 3}会创建一个整数序列,有着类型initial_list<int>
cpp std::vector<int> nums{1, 2, 3, 4, 5}; // 列表初始化 for (auto it : nums){ cout << it << endl; }
静态断言
编译时断言机制,允许在编译时检查某个条件是否为真。静态编译检查编译时的常量表达式。经常与类型特征type traits一起使用。因为静态断言是在编译时进行检验,所以可以用于不同编译平台进行运行前检验。
static_assert(<constant-expressions>, <error-message>);
static_assert(sizeof(int) >= 4, "Not support 32 bits integer");
template <typename T>
void CheckInt(T* co, size_t size)
{
static_assert(std::is_integral<T>::value, "Not support 32 bits integer.");
}
类型推导
auto类型推导的使用,必须前面有可以隐式说明类型的语句。
cpp std::vector<int> nums; for (auto it : nums){ cout << it << endl; }
lambda表达式
形如[capture list](parameter){/* code */},默认捕获到的值编译器会为其加const修饰符,内部无法修改,但是捕获到的引用可以修改。
[] // 什么都不捕获
[=] // 捕获局部对象值
[&] // 捕获局部对象的引用
[this] // 捕获this的引用
[a, &b] // 捕获a的值,捕获b的引用
auto g = [](int a, int b){ return a + b;};
decltype类型声明
decltype操作符将会返回传递给它的表达式得到的类型。
```cpp
int a = 0;
decltype(a++) b;
int a = 0;
decltype(a++) b;
template<typename T>
auto void(T a, T b) -> decltype(T){ // auto推导函数返回值,最好指定返回类型
return a + b;
}
```
类型别名
`C++`中`using`也可以声明别名,相较于`typedef`更易读。
```cpp
template <typename T, typename T>
using u_map = std::map<T, T>;
```
C++11新特性(一):语言特性的更多相关文章
- C++ 11学习和掌握 ——《深入理解C++ 11:C++11新特性解析和应用》读书笔记(一)
因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出 ...
- C++11新特性总结 (一)
1. 概述 最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力.C++ Primer5是学习C++1 ...
- 【C++11】30分钟了解C++11新特性
作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C+ ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- 在C++98基础上学习C++11新特性
自己一直用的是C++98规范来编程,对于C++11只闻其名却没用过其特性.近期因为工作的需要,需要掌握C++11的一些特性,所以查阅了一些C++11资料.因为自己有C++98的基础,所以从C++98过 ...
- C++11新特性——The C++ standard library, 2nd Edition 笔记(一)
前言 这是我阅读<The C++ standard library, 2nd Edition>所做读书笔记的第一篇.这个系列基本上会以一章一篇的节奏来写,少数以C++03为主的章节会和其它 ...
- C++11新特性之一——Lambda表达式
C++11新特性总结可以参考:http://www.cnblogs.com/pzhfei/archive/2013/03/02/CPP_new_feature.html#section_6.8 C++ ...
- c++学习书籍推荐《深入理解C++11 C++11新特性解析与应用》下载
百度云及其他网盘下载地址:点我 编辑推荐 <深入理解C++11:C++11新特性解析与应用>编辑推荐:C++标准委员会成员和IBM XL编译器中国开发团队共同撰写,权威性毋庸置疑.系统.深 ...
- Java 11 新特性介绍
Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...
- C# 3.0新语言特性和改进(一)
引言 关于C#3.0的特性,园子里已经有了一大把,可能大家都很熟悉了,虽然本人开发中使用过,但自己还是需要记录一下,总结一下.同时也是后面写Linq知识的基础.希望有兴趣的朋友,可以看看. C# 3. ...
随机推荐
- Gerrit 大量代码提交流程优化
# Gerrit 大量代码提交流程优化 背景 本文适用于 提交大量初始代码 的场景(仓库版本的早期). 有时候提交大量代码到Gerrit的时候会提示: $ git push Counting obje ...
- 在KEIL中用JTAG仿真出错:error:cannot load driver".....JL2CM3.dll" 时的解决方法
在KEIL中用JTAG仿真出错:error:cannot load driver".....JL2CM3.dll" 时的解决方法 报错: Error:Cannot load dri ...
- .NET周刊【6月第4期 2024-06-23】
国内文章 C#.Net筑基-集合知识全解 https://www.cnblogs.com/anding/p/18229596 .Net中提供了数组.列表.字典等多种集合类型,分为泛型和非泛型集合.泛型 ...
- 【workerman】uniapp+thinkPHP5使用GatewayWorker实现实时通讯
前言 之前公司需要一个内部的通讯软件,就叫我做一个.通讯软件嘛,就离不开通讯了,然后我就想到了长连接.这里本人用的是GatewayWorker框架. 什么是GatewayWorker框架? Gatew ...
- SeaweedFS + TiKV 部署保姆级教程
在使用 JuiceFS 时,我们选择了 SeaweedFS 作为对象存储,以及 TiKV 作为元数据存储,目前在 SeaweedFS 上已经存储了近1.5PB 的数据.关于 SeaweedFS 和 T ...
- Swift开发基础07-内存布局
了解Swift的内存布局和底层原理对于编写高性能和内存高效的应用非常重要.接下来,我将更详细地介绍Swift的内存管理机制和一些底层实现细节,包括内存布局.ARC(自动引用计数).引用类型和值类型的区 ...
- Day 9 - 线段树
线段树 引入 线段树是算法竞赛中常用的用来维护 区间信息 的数据结构. 线段树可以在 \(O(\log N)\) 的时间复杂度内实现单点修改.区间修改.区间查询(区间求和,求区间最大值,求区间最小值) ...
- Python pluggy框架基础用法总结
代码为例进行说明 实践环境 Python 3.6.5 pluggy 0.13.0 例1 注册类函数为插件函数 #!/usr/bin/env python # -*- coding:utf-8 -*- ...
- 前端使用 Konva 实现可视化设计器(18)- 素材嵌套 - 加载阶段
本章主要实现素材的嵌套(加载阶段)这意味着可以拖入画布的对象,不只是图片素材,还可以是嵌套的图片和图形. 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,欢迎来提 Issue ...
- 图灵课堂netty 仿微信开发
通信的图文示例 以下是需要实现的前端界面, 准备工作:开始实现前需要技术关健字解释 第一步,这儿直接建一个maven 项目 就好,只要是可能用maven 管理包的环境就行,课程使用的版本是 java ...