C++11新特性(一):语言特性

news/2024/9/18 8:52:42/文章来源:https://www.cnblogs.com/solicit/p/18353079

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::moveclass 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 valueMyClass&& 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 0MyClass(MyClass& obj){ // 拷贝构造函数,浅拷贝cout << "left value" << endl;data = obj.data; // 只复制指针的值}
#elseMyClass(MyClass& obj){ // 拷贝构造函数,深拷贝cout << "left value" << endl;data = new int(*obj.data); // 分配内存、赋值为就对象的资源并返回一个指针给data}
#endifMyClass(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 valueMyClass&& 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操作符将会返回传递给它的表达式得到的类型。

int a = 0;
decltype(a++) b;
// 以下函数定义方式是错误的,因为decltye无法推导函数返回类型,这是因为在函数外部,a和b是未定义
decltype(a + b) Func(int a, int b){return a + b;
}// c++14后支持
auto Func(int a, int b) -> decltype(a + b){return a + b;
}
template<typename T>
auto void(T a, T b) -> decltype(T){ // auto推导函数返回值,最好指定返回类型return a + b;
}

类型别名

C++using也可以声明别名,相较于typedef更易读。

template <typename T, typename T>
using u_map = std::map<T, T>;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/786463.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电脑更新有什么好处和坏处,怎么更新电脑呢

电脑更新,特别是操作系统和软件的更新,带来了多方面的好处和坏处。下面分别讨论这些方面,并介绍如何进行电脑更新。 一、好处: 1.安全性增强:系统更新通常包含安全补丁,用于修复已知的安全漏洞,保护你的电脑免受恶意软件和黑客攻击。 2.性能改进:软件开发者会不断优化软…

WPF 的 await Application.Current.Dispatcher.InvokeAsync,Func 如果是Task , 等待赋值可能存在没有等待执行完成的问题

最近在检查我们组内的代码,发现好多用到await Application.Current.Dispatcher.InvokeAsync 相信好多WPF的开发都会用到 该方法做UI线程切换。但是细看里边的执行,发现了个别存在存在没有等待完成的情况 执行的结果是 i 为 null 值。 这也就说明了 执行了await Application.C…

dotnet 默认创建的 JsonContent 没有 Content Length 的内容头

本文记录一个 dotnet 的设计问题,默认创建出来的 JsonContent 对象的 Headers 里,是没有 Content-Length 信息的如下面代码创建一个 JsonContent 对象 using System.Net.Http.Json;var foo = new Foo();var jsonContent = JsonContent.Create(foo);class Foo {public int Val…

《Programming from the Ground Up》阅读笔记:p95-p102

《Programming from the Ground Up》学习第6天,p95-p102总结,总计8页。 一、技术总结 1.directive(伪指令) 很多资料喜欢把directive和instruction都翻译成“指令”,这样在看到指令这个词时就不知道到底指的是什么?这里参考其它人的做法,将directive称为“伪指令”。 2.re…

如何在 Nuxt 中动态设置页面布局

title: 如何在 Nuxt 中动态设置页面布局 date: 2024/8/24 updated: 2024/8/24 author: cmdragon excerpt: 摘要:本文介绍如何在Nuxt框架中通过设置setPageLayout函数动态调整页面布局,包括安装Nuxt、创建不同布局文件及中间件,并通过示例演示如何根据不同路径设置相应布局…

牛客小白月赛99

牛客小白月赛99\(A\) 牛客 NC275617 材料打印 \(AC\)\(by+a \times \min(x,y)\) 即为所求。点击查看代码 int main() {ll t,a,b,x,y,i;cin>>t;for(i=1;i<=t;i++){cin>>a>>b>>x>>y;cout<<b*y+a*min(x,y)<<endl;}return 0; }\(B\) …

SQL Server 数据库 优化 性能瓶颈

优化sql查询,分库分表,读写分离。 建立索引,分页,时间段不要太长(限制数量)。 升级电脑:固态硬盘,多个cpu,万兆网口。 超级大表等优化。一查询,磁盘 100%lock select * from xx (nolock) 预防为主,测试为重。 建立模拟环境(测试环境),一模一样的应用环境,提前测…

线性dp:大盗阿福(打家劫舍)

大盗阿福本题与leetcode198题——打家劫舍的题意一模一样,阅读完本文以后可以尝试以下题目力扣题目链接) 题目叙述: 阿福是一名经验丰富的大盗。趁着月黑风高,阿福打算今晚洗劫一条街上的店铺。这条街上一共有N家店铺,每家店中都有一些现金。阿福事先调查得知,只有当他同时…

Nexpose v6.6.266 for Linux Windows - 漏洞扫描

Nexpose v6.6.266 for Linux & Windows - 漏洞扫描Nexpose v6.6.266 for Linux & Windows - 漏洞扫描 Rapid7 Vulnerability Management, release Aug 21, 2024 请访问原文链接:https://sysin.org/blog/nexpose-6/,查看最新版。原创作品,转载请保留出处。 作者主页:…