C++11 常用的新特性

news2024/9/20 12:52:52

        本篇介绍C++11标准对比之前C++标准的新特性,C++11为C++语言在2011年发布的版本,它改进幅度很大,影响至今。如加入auto 关键字、nullptr、移动语义(move semantics)、委托构造函数(delegating constructors)、默认构造函数(default constructor)、类型别名(type alias)、右值引用(rvalue reference)、Lambda 表达式(lambda expressions)、静态断言(static_assert)、新的数值类型(new numerical types)、智能指针(smart pointers)、并发库(concurrency library)等。本篇简单介绍一下这些常用的内容。

 

目录

一、auto关键字

1.1 自动推断变量类型

1.2 auto与模板函数结合使用

 二、nullptr空指针

三、移动语义(move semantics)

3.1 移动语义介绍

3.2 移动语义的实现

四、委托构造函数(delegating constructors)

五、默认构造函数

六、类型别名(type alias)

6.1 typedef

6.2 using

七、右值引用(rvalue reference)

八、Lambda 表达式(lambda expressions)

九、静态断言(static_assert)

十、智能指针(smart pointers)

十一、并发库(concurrency library)


一、auto关键字

1.1 自动推断变量类型

        auto可以自动推断变量的类型。它通过分析变量初始化表达式的类型来确定变量的类型。这样可以简化代码,减少类型的显式声明,提高代码的可读性。

eg:

auto x = 10;  // x的类型为int
auto y = 3.14;  // y的类型为double

        auto还可简化模版代码:

template<typename T>
void func(T t) {
    auto x = t + 1;  // x的类型与t的类型相同
    // ...
}

        自动推断迭代器类型:

std::vector<int> v = {1, 2, 3, 4, 5};
for (auto it = v.begin(); it != v.end(); ++it) {
    // ...
}

         自动推断lambda函数返回类型:

auto func = [] (int a, int b) { return a + b; };

        自动推断类型构造函数的返回类型:

struct A {
    int x, y;
};

auto func() {
    return A{1, 2};
}

        在上面的代码中,函数func返回了一个类型构造函数A的结果,但是我们并不需要显式地声明返回类型,编译器会自动推断出返回类型为A。 这样做可以使代码更简洁易读,同时还可以避免因为类型改变导致的类型错误。

1.2 auto与模板函数结合使用

        auto和模板函数结合使用可以实现自动推断函数返回类型,从而使代码更简洁易读。

template<typename T>
auto max(T a, T b) -> decltype(a > b ? a : b)
{
    return a > b ? a : b;
}
  • template<typename T>:声明模板函数,T表示模板参数类型。
  • auto max(T a, T b):定义函数名为max,接收两个参数a和b,返回类型为auto。
  • -> decltype(a > b ? a : b):使用decltype关键字指定函数的返回类型。

Tips

    decltype(a > b ? a : b)是C++中的decltype关键字,用于指定函数的返回类型。它的作用是根据表达式的类型推断出函数的返回类型。在上面的代码中,a > b ? a : b是一个三元表达式,表示如果a大于b,则返回a,否则返回b。decltype关键字可以推断出这个三元表达式的类型,并作为函数的返回类型。

        这样,我们可以使用decltype指定函数返回类型,避免手动编写长且复杂的类型名称,提高代码可读性。

  • return a > b ? a : b;:返回两个数的最大值。

 二、nullptr空指针

   nullptr是C++11引入的新特性,代表一个空指针常量。它可以明确地表示空指针,比起使用NULL或0更加明确和安全。

        在C++11之前,使用NULL表示空指针,但是他是整数,存在类型转换问题,例如:

void foo(int);
void foo(char*);

foo(NULL);

        代码在C++98无法编译通过,因为编译器无法确定调用的是foo(int)还是foo(char*)。但是,使用nullptr就可以解决这个问题:

foo(nullptr);

        编译器可以确定调用的是foo(char*),这样就可以避免类型转换问题。所以,使用nullptr比使用NULL更加明确和安全,建议在C++11及以后的代码中使用nullptr来表示空指针常量。

三、移动语义(move semantics)

3.1 移动语义介绍

        移动语义是C++11新出的特性,可以实现快速资源转移,在C++中对象的赋值和传递一般需要复制对象内容:

Tips

        在C++中,对象之间的赋值和传递操作一般需要复制对象内容。这意味着,如果你将一个对象的值赋给另一个对象,或者将一个对象作为参数传递给函数,那么这两个对象的内容会被复制。

        在C++中,所有的数据类型(包括内置类型和自定义类型)都是对象。因此,如果你赋值一个int类型的变量给另一个int类型的变量,或者将一个int类型的变量作为参数传递给函数,那么这两个int类型的变量的值会被复制。同样,如果你赋值一个自定义类型的对象给另一个自定义类型的对象,或者将一个自定义类型的对象作为参数传递给函数,那么这两个自定义类型的对象的值也会被复制。

        这种复制行为可能导致代码慢,特别是在处理大对象时。因此,C++提供了一些特殊的方法,如引用和指针,来优化对象之间的赋值和传递操作。这些方法不需要复制对象内容,而是通过指向对象内存的指针或引用实现赋值和传递。

 如果对象特别大会造成性能损失,移动语义提供了一种途径,在不复制对象内容的情况下,快速转移对象资源,从而解决性能问题。

        移动语义的实现需要使用C++11的移动构造函数和移动赋值运算符,通过标记对象为可移动对象,告诉编译器在赋值或传递操作时,不要进行复制,而是直接转移资源。

eg:

vector<int> v1 = {1, 2, 3};
vector<int> v2 = move(v1);

        在这段代码中,v1是源对象,v2是目标对象。通过使用移动语法(move),可以快速转移v1中的资源到v2中,不需要复制内容,从而提高性能。

完整代码示例:

#include <iostream>
#include <vector>
#include <utility>

using namespace std;

int main()
{
    vector<int> v1 = {1, 2, 3};
    cout << "v1 size: " << v1.size() << endl;

    vector<int> v2 = move(v1);
    cout << "v2 size: " << v2.size() << endl;
    cout << "v1 size: " << v1.size() << endl;

    return 0;
}

3.2 移动语义的实现

        C++移动语义是通过重载"="操作符移动构造函数实现的。

        以下是移动构造函数的代码实现:

class MyClass
{
public:
    MyClass(MyClass&& other)
    {
        // 移动资源的代码
    }
};
Tips
        "MyClass&& other" 是一个右值引用,它指向一个右值(临时对象)。右值引用通常用于移动语义,它允许在不拷贝数据的情况下从一个对象转移到另一个对象。在上面的代码中,"MyClass&& other" 表示移动构造函数的参数,它是一个右值,可以通过移动语义在不复制数据的情况下从一个对象转移到另一个对象。
        右值是表达式的一种结果,它代表一个不可变的、临时的、只用于赋值一次的值。右值通常是存储在程序栈上的数据,而不是存储在堆上或全局内存中的数据。右值可以是一个常量、字面值或者是一个表达式,但不能直接访问它们。右值通常通过移动语义从一个对象转移到另一个对象,从而避免了不必要的数据拷贝。

        操作符重载:

class MyClass
{
public:
    MyClass& operator=(MyClass&& other)
    {
        // 移动资源的代码
        return *this;
    }
};

四、委托构造函数(delegating constructors)

        委托构造函数是指在 C++11 中,一个构造函数能够调用另一个同类的构造函数,以初始化对象。这样可以避免在多个构造函数间重复的代码,提高代码的可读性和可维护性。语法格式为:

构造函数名(参数列表):类名(同一类的其他构造函数的参数列表){ //其他代码 }。

代码示例:

class MyClass {
 public:
  MyClass() : MyClass(0, 0) {}  // 委托构造函数,调用下面的构造函数
  MyClass(int x, int y) : x_(x), y_(y) {}
  int x_, y_;
};

 下面是一个委托构造函数的妙用的示例:

class ComplexNumber {
 public:
  // 默认构造函数,使用委托构造函数初始化实部和虚部为 0
  ComplexNumber() : ComplexNumber(0, 0) {}
  // 委托构造函数,调用下面的构造函数
  ComplexNumber(double real, double imag) : real_(real), imag_(imag) {}
  // 委托构造函数,调用下面的构造函数,把另一个复数的值赋给新的复数对象
  ComplexNumber(const ComplexNumber &other)
      : ComplexNumber(other.real_, other.imag_) {}
  double real_, imag_;
};

        在这个示例中,我们可以看到三个构造函数,其中两个构造函数是委托构造函数。默认构造函数委托初始化实部和虚部为 0 的构造函数。另一个委托构造函数把另一个复数的实部和虚部赋给新的复数对象。因此,我们可以避免在多个构造函数间重复的代码。

五、默认构造函数

        这个大家应该很熟悉了,很难想象之前没有默认构造函数,C++er的处境。

六、类型别名(type alias)

        类型别名(type alias)是指为一个已经存在的类型创建一个新的名称。可以使用关键字 typedefusing 实现。

6.1 typedef

        使用 typedef 的方式如下:

typedef int MyInt;
MyInt i = 5;

6.2 using

        使用 using 的方式如下:

using MyInt = int;
MyInt i = 5;

七、右值引用(rvalue reference)

        右值引用是 C++11 引入的一种引用类型,它是一个可以指向右值的引用。右值引用可以帮助我们实现移动语义。

        语法:

int&& rvalueRef = 5;

        也可以利用右值引用实现移动语义,例如:

std::string getName() { return std::string("Alex"); }

int main() {
  std::string&& name = getName();
  std::cout << name << std::endl;
  return 0;
}

        实际上,在调用 getName() 时,返回的是一个右值,而在给右值引用 name 赋值时,移动语义就可以得到实现。 

八、Lambda 表达式(lambda expressions)

        如下链接:

https://bobowen.blog.csdn.net/article/details/128696518?spm=1001.2014.3001.5502

九、静态断言(static_assert)

        静态断言是C++11引入的一种编译期断言。它在编译期间评估一个常量表达式,并在表达式为false时生成编译错误。静态断言的语法是:

static_assert(expression, message);

        其中expression是一个常量表达式,message是一个字符串常量,用于描述错误的原因。

        代码示例:

#include <iostream>

int main()
{
    static_assert(2 + 2 == 4, "2 + 2 should equal 4");
    std::cout << "Compilation succeeded\n";
    return 0;
}

        这个代码编译时不会出错,但是如果将表达式改为2 + 2 != 4,就会生成编译错误,并显示错误消息"2 + 2 should equal 4"。

        错误示例:

         直接编译不通过,还是挺厉害的功能。

十、智能指针(smart pointers)

        如下链接:

https://bobowen.blog.csdn.net/article/details/128714630?spm=1001.2014.3001.5502

十一、并发库(concurrency library)

        C++11 标准引入了并发库(concurrency library),它提供了一组用于管理多线程的组件,包括线程、锁、同步原语、异步任务和其他工具。并发库的目的是简化多线程编程,使开发人员能够更容易地创建高效的多线程应用程序。它可以帮助开发人员避免常见的多线程错误,如死锁、竞争条件和数据不一致。

        代码示例:

#include <iostream>
#include <thread>

void print_message(const char* message) {
    std::cout << message << std::endl;
}

int main() {
    std::thread t(print_message, "Hello from thread");
    t.join();
    return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ChatGPT超详细注册与使用教程

文章目录前言一、ChatGPT账号注册二、SMS-ACTIVATE虚拟手机号验证三、ChatGPT使用总结前言 最近ChatGPT非常火爆&#xff0c;是一种革命性的技术&#xff0c;这也吸引来了很多人想尝试一下&#xff0c;但是由于并没有在国内开通这项服务&#xff0c;所以国内的用户无法使用Chat…

Javascript预解析

1.我们js引擎运行js 分为两步&#xff0c;1.预解析&#xff0c;2.执行代码 &#xff08;1&#xff09;预解析&#xff1a;js引擎会把js里面所有的var还有function提升到当前作用域发的前面 &#xff08;2&#xff09;执行代码&#xff1a;按照代码书写的顺序从上往下执行 2.预…

RK3588平台开发系列讲解(进程篇)进程的处理器亲和性

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、简介二、相关结构体三、函数接口四、cpuset的使用沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇介绍进程的处理器亲和性相关知识。 一、简介 Linux进程调度器为了充分利用CPU资源,会将进程在不同的…

如何养成整洁的代码习惯

如何养成整洁的代码习惯前言1.为什么要保持代码整洁?1.1 所以从一开始就要保持整洁1.2 如何写出整洁的代码?2.命名2.1 不好的命名方式1.没有任何意义的命名方式2.命名前后不一致3.命名冗余3.类3.1单一职责3.2 开闭原则3.3 内聚4.函数4.1 只做一件事4.2 函数命名1.函数名应见名…

春季开学必备物品清单、数码好物推荐篇

开学的脚步近了&#xff0c;近了&#xff0c;大学生返校&#xff0c;万物更新&#xff0c;大家迎接开学季的阵仗堪比迎接春天了。灵魂发问&#xff1a;开学装备备齐了吗&#xff1f;大学生们的情绪调整好了吗&#xff1f;自己要不要再回回炉&#xff0c;充充电&#xff1f;这次…

【redis6】第十二章(持久化)

RDB RDB是什么 在指定的时间间隔内将内存中的数据集快照写入磁盘&#xff0c; 也就是行话讲的SNAPSHOT快照&#xff0c;它恢复时是将快照文件直接读到内存里 备份是如何执行的 Redis会单独创建&#xff08;fork&#xff09;一个子进程来进行持久化&#xff0c;会先将数据写…

ARM学习(17)ARM函数调用规则

笔者来聊聊ARM的函数的调用规则 你好&#xff01; 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章&#xff0c;了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持&…

观点动力学模型:主要理论与模型综述

文章目录意见动态建模图论DeGroot 模型Friedkin-Johnsen models社会权力演变自我评价反映的演变DeGroot-Friedkin模型(DeGroot)的新研究最终社会权力的分析动态相对互动拓扑相似时间尺度&#xff0c;记忆和噪声表达观点(expressed opinion)和私人观点(private opinion)EPO模型意…

学完python再学Java顺利吗,学完python再学Java要多久

这篇文章主要介绍了学完python再学C会不会轻松一点&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 1、学编程先学python&#xff0c;然后学java可以吗&#xff1f; 建议先学J…

solidity Dapp 从签名中提取消息签名地址

通常, ECDSA&#xff08;椭圆曲线数字签名算法&#xff09;包含两个参数, r 和 s. 在以太坊中签名包含第三个参数 v,它可以用于验证哪一个账号的私钥签署了这个消息。 Solidity 提供了一个内建函数 ecrecover 它接受 r, s and v 作为参数并且返回签名这的地址。我们如何进行测试…

Windows使用WinSW实现开机自启动服务

在windwos系统中&#xff0c;有时候需要java的jar开机自启动&#xff0c;或者nginx的开机自启动&#xff0c;或者内网穿透工具(frp)的开机自启动&#xff0c;使用WinSW是一种很好的选择&#xff0c;记录一下使用WinSW实现的方式WinSW开源和下载地址&#xff08;最新版WinSW v2.…

从0开始学python -14

Python3 字符串 -1 字符串是 Python 中最常用的数据类型。我们可以使用引号( ’ 或 " )来创建字符串。 创建字符串很简单&#xff0c;只要为变量分配一个值即可。例如&#xff1a; var1 Hello World! var2 "Runoob"Python 访问字符串中的值 Python 不支持…

Springboot2.x+Websocket+js实现实时在线文本协同编辑,并展示协同用户

文章目录诉求相关技术思路展开相关步骤pom配置服务端相关配置文本信息、用户广播处理逻辑前端功能代码功能测试小结诉求 实现页面实时在线文本协同编辑,且显示当前同时编辑文本的用户。 相关技术 Springboot(2.7.0)Websocketjavascript 思路展开 页面展示当前登陆用户页面有…

NANK南卡护眼台灯Pro新品测评:旗舰级护眼,降低80%近视风险!

对于重度熬夜患者来说&#xff0c;对于家居用品是非常偏爱的&#xff0c;而最主要的就是光源问题&#xff0c;护眼台灯的发展迅速&#xff0c;不再局限于简单照明&#xff0c;在写作和办公、绘画的场景都适用&#xff0c;经常在电脑桌上的我&#xff0c;就看到了这款旗舰级专业…

9个 Intellij IDEA中使用Debug调试详解

有人说&#xff1a;一个人从1岁活到80岁很平凡&#xff0c;但如果从80岁倒着活&#xff0c;那么一半以上的人都可能不凡。 生活没有捷径&#xff0c;我们踩过的坑都成为了生活的经验&#xff0c;这些经验越早知道&#xff0c;你要走的弯路就会越少。 Debug用来追踪代码的运行流…

java数据输入

数据输入1.1数据输入概述1.2 Scanner使用的基本步骤导包创建对象接收数据

Windows内核--任务、进程和线程(2.4)

图片来自: Windows内核原理与实现 Windows内核有"任务"概念吗? 从技术术语来说&#xff0c;Windows内核并没有"任务"。"任务"一般被认为是抽象的需要执行的事情。在不同操作系统上&#xff0c;"任务"所代表的官方名称有所差异。 Linu…

树形表查询

树形表: 情况一:固定层级的树形表: 可以使用表的自连接查询,比如查询两级分类课程 selectone.id one_id,one.name one_name,one.parentid one_parentid,one.orderby one_orderby,one.label one_label,two.id two_id,two.name two_name,two.parentid two_parentid,two.orderby …

系统公告 | MemFire Cloud应用管理全新升级,实时数据库等你来体验~

“超能力”数据库&#xff5e;拿来即用&#xff0c;应用开发人员再也不用为撰写API而发愁。MemFire Cloud 为开发者提供了简单易用的云数据库&#xff08;表编辑器、自动生成API、SQL编辑器、备份恢复、托管运维&#xff09;&#xff0c;很大地降低开发者的使用门槛。 MemFire …

计算机视觉OpenCv学习系列:第九部分、视频读写

第九部分、视频读写第一节、视频读写处理1.视频标准与格式2.视频读写与函数3.代码练习与测试学习参考第一节、视频读写处理 1.视频标准与格式 视频标准与格式&#xff1a; SD(Standard Definition)标清480PHD(High Definition)高清720P/1080PUHD(Ultra High Definition)超高清…