C++11标准-详解

news2025/1/13 13:53:46

目录

1、列表初始化

2、隐式类型转换

1)概念理解

2)举例增进理解

3)隐式与显式区别?

a、直接初始化 vs 拷贝初始化

b、构造函数调用

c、语义上的差异

d、性能差异

4)explicit 关键字

5)多参数的隐式类型转换?

a、概念理解

b、举例增进理解

3、initializer_list参数

1)概念理解

2)initializer_list的底层

3)用法

4、decltype关键字

1)概念理解

2)用法

5、右值引用

1)语法格式

2)概念理解

3)转移构造

4)完美转发

5)移动赋值

6、万能引用

7、lambada表达式

1)格式

2)细节

8、模板可变参数

9、包装器


1、列表初始化

不是初始化列表(构造函数部分)

目的:一切都可以使用列表初始化,可以省略赋值符号=

	//初始化列表形式的初始化,但是没有什么很实际的用处
	int a{1};
	char ch{'a'};
	string s{ "hello,world" };
	vector<int>v{1,2,3,4,5};
	list<string>s{"math","China","English"};

2、隐式类型转换

1)概念理解

什么是隐式类型转换?

2)举例增进理解

理解了吗?我想没有。举一个例子:


class A {
public:
	A(int a)
		:_a(a)
	{
	}

private:
	int _a;
};

int main()
{
	A a1 = 1;


	return 0;
}

这里有一个自定义类型A,他的成员变量只有一个int
按理来说,A是自定义类型,1是int类型,是不可以这样定义的。
正常的初始化A是什么样的呢?
应该是这样子的:

	//显式调用了A的构造函数,然后再将构造出来的这个对象,拷贝赋值给我们的a
	A a =  A(1);

这是显式的调用了A的构造函数,然后再将构造出来的这个对象,再拷贝赋值给我们的对象a
也就是说,这简单的一个语句,经过2个阶段:
1、构造函数构造对象
2、拷贝赋值给a(但是事实上,不一定会使用拷贝复制,可能会优化,这个要看编译器,或者直接使用移动构造)


而第一种初始化方式:

//编译器使用A的构造函数将整数 1 转换为类型 A 的临时对象
A a1 = 1;

他没有按照正常的流程走
没有显式调用构造,而是直接给了一个int值1
那么这个期间发生了什么?
这种初始化方式就是隐式类型转换,因为整数 1 被自动转换为 A 类型对象
编译器查找到了类 A 中的一个构造函数 A(int a),该构造函数接受一个整型参数。
编译器使用这个构造函数将整数 1 转换为类型 A 的临时对象。
最后,编译器使用拷贝初始化的方式将这个临时对象拷贝构造到 a1 中,完成了整个初始化过程
简单来说,也是经过了两个过程:
1、构造函数构造临时对象
2、拷贝赋值给a1

3)隐式与显式区别?

都是先构造,再拷贝,那么区别是什么?

a、直接初始化 vs 拷贝初始化

A a1 = 1; 使用的是拷贝初始化方式。
A a = A(1); 使用的是直接初始化方式。

b、构造函数调用

拷贝初始化可能会调用拷贝构造函数,将临时对象复制给目标对象。
直接初始化则是直接调用相应的构造函数来创建对象,不一定会调用拷贝构造函数。在这种情况下,也可能调用移动构造函数或其他相关的构造函数。

c、语义上的差异

拷贝初始化通常用于通过已有对象创建一个新对象,其语义上暗示着创建一个新的对象并将其初始化为与另一个对象相同的值。
直接初始化则更加明确,通常用于显式地调用特定的构造函数来创建对象。

d、性能差异

直接初始化可能比拷贝初始化更加高效,因为它不需要额外的拷贝步骤,尤其是在C++11及以后版本中,当涉及到移动语义时。
拷贝初始化可能会导致不必要的对象复制,特别是在某些情况下,例如临时对象的创建和销毁,以及不必要的复制操作。

4)explicit 关键字

explicit 是 C++ 中的一个关键字,用于修饰单参数的构造函数,用于防止隐式类型转换。当一个构造函数被声明为 explicit 时,它将不再参与隐式类型转换,只能被用于显式地创建对象。

class A {
public:
	explicit A(int a)
		:_a(a)
	{
	}
private:
	int _a;
};

int main()
{
	A a = 1;//会报错
	return 0;
}

5)多参数的隐式类型转换?

a、概念理解

对于多参数构造函数来说,它们本身就不会参与隐式类型转换,因为在调用时必须显式地提供所有参数。隐式类型转换指的是将一种类型转换为另一种类型的过程,而不需要显式的构造函数调用。一般发生在单参数构造函数的情况下,因为单参数构造函数可以被用于将一种类型隐式地转换为另一种类型。

b、举例增进理解

举个例子,假设有一个类 MyClass 和一个单参数构造函数,可以将 int 类型的参数转换为 MyClass 类型:

class MyClass {
public:
    MyClass(int x) {
        // 构造函数的实现
    }
};

如果你写成 MyClass obj = 10;
编译器会自动调用 MyClass 的构造函数,将 10 这个 int 类型的参数隐式地转换为 MyClass 类型。
这就是隐式类型转换。

然而,对于多参数构造函数,比如:

class MyClass {
public:
    MyClass(int x, double y) {
        // 构造函数的实现
    }
};

如果你写下 MyClass obj = 10;
这是不合法的,因为编译器无法将 10 这个 int 类型的参数隐式地转换为 MyClass 类型,因为缺少必要的参数。
必须显式地提供构造函数所需的所有参数,
例如 MyClass obj(10, 3.14);

MyClass obj(10, 3.14);

因此,多参数构造函数本身并不会导致隐式类型转换,因为等号后面只能跟一个参数,但这个是多参数的。你必须提供所有参数,并显式调用构造函数才能创建对象。

3、initializer_list参数

1)概念理解

initializer_list 是 C++11 中引入的一种特殊类型,用于表示一组同类型的值的列表。一般用于初始化容器类对象(如 std::vectorstd::initializer_list 等)或者自定义类型的构造函数。

例如对于vector初始化的初始化:

如果初始化数据个数是不确定的

如果按照隐式类型转换的方式来支持列表初始化

因为列表初始化的过程是:构造函数+拷贝构造

而构造函数要保证有对应匹配参数个数

这就会导致构造函数冗余,

因此设置一个参数,即initializer_list

2)initializer_list的底层

它的内部空间有两个指针

它不开空间,而是指向一个常量数组的开始数据和最后数据的下一个位置

事实上其原理很简单

就是其中一个构造函数的参数设置为initializer_list

然后对应的for循环,push_back即可

initializer_list是一个指向常量数组类型的容器

内部有两个变量,指向常量数组的开始和最后位置

3)用法

一般使用在构造函数中

class MyClass {
public:
    MyClass(std::initializer_list<int> list) {
        // 构造函数的实现
    }
};

int main() {
    MyClass obj1{1, 2, 3}; // 使用 initializer_list 初始化对象
    MyClass obj2 = {4, 5, 6}; // 也可以使用赋值语句初始化对象
    return 0;
}

4、decltype关键字

1)概念理解

decltype 是 C++11 中引入的一个关键字,用于获取表达式的数据类型。

其实也是为了解决auto自动推导类型的麻烦,互补(非必要不建议使用,自从c++14允许auto可以推导返回值之后,就是一个大坑)

2)用法

  • 推断变量的类型
  • int x = 5;
    decltype(x) y; // y 的类型为 int
  • 推断函数返回值的类型
  • int func() { return 10; }
    decltype(func()) result; // result 的类型为 int

    推断表达式的类型,包括引用类型和 const 修饰

  • const int& ref = x;
     decltype(ref) z = y; 
    // z 的类型为 const int&

    推断模板参数的类型

  • template<typename T, typename U>
    auto add(T t, U u) -> decltype(t + u)
    { return t + u; }
  • 在这个例子中,decltype(t + u) 用于推断 add 函数的返回类型,它将返回 t 和 u 相加后的类型。

5、右值引用

1)语法格式

int&& a = 10;//int&&是一个右值引用
int& b = a;//int&是一个左值引用

2)概念理解

右值引用是 C++11 中引入的一个特性,用于支持移动语义和完美转发

左值:可以取地址

右值:不可以取地址,不能被赋值

左值引用就是对左值取别名,右值引用就是对右值取别名

左值能否作为右值的引用?不可以,但是const可以

右值能否作为左值的引用?不可以,但是move以后的左值可以(move:从左值转换成右值)

右值一般有:临时变量、匿名对象

左值右值都有地址,左值可以取,右值不可以取

右值引用本身是左值

交换的swap的参数是一个左值

3)转移构造

参数为右值的构造函数叫做移动构造,延长资源的生命周期,移动构造其实是资源的转移。

转移构造函数(Move Constructor)是 C++11 中引入的一个特殊构造函数,用于实现移动语义移动语义允许在不进行深拷贝的情况下将资源(如动态分配的内存)从一个对象转移到另一个对象。通过将资源的所有权从一个临时对象(右值)转移到另一个对象,可以避免额外的内存分配和拷贝操作。

对于右值来说,既然你是一个即将被销毁的值(右值),没用了。但对于另一个对象来说,你是一个待用的值。对你没用,但是对我来说正好就是要用的。所以,在你还没有被销毁之前就直接交换。这就不用再构造、拷贝。

4)完美转发

在 C++ 中,函数传递参数时,常常需要考虑到参数的值类型、引用类型、常量修饰符等。而且,有时候我们希望在函数中传递参数给其他函数时,能够保留原始参数的类型和属性,即使它是一个临时对象(右值)或者一个具名对象(左值)。

完美转发的核心作用是将参数原封不动地传递给其他函数,无论参数是左值还是右值,都能保留其值类型

格式

template<typename T>
void forwarder(T&& arg) {
    target(std::forward<T>(arg));
}

forwarder 函数模板接受一个参数 arg,并通过 std::forward 将参数完美转发给另一个函数 target

5)移动赋值

ClassName& operator=(ClassName&& other)  {
    if (this != &other) {
        // 释放当前对象的资源
        // 转移其他对象的资源到当前对象
    }
    return *this;
}

移动赋值的主要作用是实现对象之间的资源转移,而不进行深拷贝操作

6、万能引用

万能引用是一个在模板函数中的一种特殊的引用类型。

T&&当作为参数时,不是右值引用,而是万能引用。怎么理解?

很简单,当传递左值时,T 被推导为左值引用类型,当传递右值时,T 被推导为非引用类型。

template<typename T>
void fun(T&& arg) {
    // ...
}

7、lambada表达式

1)格式

由捕捉列表,参数列表,返回值,函数体四部分构成


[capture list] (parameters) -> return_type {
    // Lambda 表达式的函数体
}

capture list:捕获列表,用于捕获外部变量,可以为空或包含零个或多个变量。捕获列表通过值捕获或引用捕获外部变量。
parameters:参数列表,类似于普通函数的参数列表,可以为空或包含零个或多个参数。
return_type:返回类型,指定 Lambda 表达式的返回类型,可以省略,编译器会根据上下文自动推导返回类型。
{}:Lambda 表达式的函数体,包含具体的操作逻辑

lambada的本质是仿函数,是一个匿名函数对象

其类型不知道,只有编译器知道

为什么会有lambda表达式?

因为仿函数的是书写太麻烦了,要单独写一个类,然后再匿名对象传参

不如直接使用表达式作为参数

2)细节

捕捉列表捕捉当前域的对象(传值传参,叫做传值捕捉)

可以修改,但是修改a,b是拷贝过来的(传值),所以不改变外面的值

int main() {
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;

【&a,&b】引用方式捕捉


    // 引用捕捉:修改 a、b 会影响外部变量
    auto func2 = [&a, &b]() {
        a = 1000;
        b = 2000;
        };

【=】捕捉所有变量

 // 捕捉所有变量:传值捕捉,修改 a、b 不会影响外部变量
 auto func3 = [=]() mutable {
     a = 10000;
     b = 20000;
     };

【&】引用的方式捕捉所有变量

 // 引用的方式捕捉所有变量:修改 a、b 会影响外部变量
 auto func4 = [&]() {
     a = 100000;
     b = 200000;
     };

【&a,b】混合捕捉:a为引用捕捉,b为传值捕捉

// 混合捕捉:a 为引用捕捉,b 为传值捕捉
auto func6 = [&a, b]() mutable {
    a = 1000000;
    b = 2000000;
    };

函数 = delete:不允许这个函数被调用

8、模板可变参数

可变参数模板是C++中的一个特性,它允许在模板中接受数量不定的参数。

#include <iostream>

// 基本情况:递归终止条件
void print() {
    std::cout << std::endl;
}

// 可变参数模板:递归展开参数包
template<typename T, typename... Args>
void print(T first, Args... args) {
    std::cout << first << " ";
    print(args...);
}

int main() {
    print(1, 2, 3, 4, 5);
    print("Hello", "World", "!");
    return 0;
}

9、包装器

一个栈帧内部的临时对象,如果比较小,存在寄存器;比较大,存在两个栈帧之间

这个叫做压参数/压栈帧

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

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

相关文章

HarmonyOS(二十五)——Harmonyos通用事件之点击事件

组件被点击时触发的事件就是点击事件。 1.事件 名称支持冒泡功能描述onClick(event: (event?: ClickEvent) > void)否点击动作触发该回调&#xff0c;event返回值见ClickEvent对象说明。从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 2.ClickEvent对象…

C++青少年简明教程:字符类型、字符数组和字符串

C青少年简明教程&#xff1a;字符类型、字符数组和字符串 在 C 语言中&#xff0c;处理文本数据的基础是字符类型 char&#xff0c;字符数组&#xff0c;以及标凌库中的字符串类 std::string。 C中的char类型占用 1 字节的内存空间&#xff0c;用于存储单个ASCII字符。例如&a…

【Pytorch】计算机视觉项目——卷积神经网络TinyVGG模型图像分类(如何使用自定义数据集)

目录 一、前言二、工作流程回顾三、详细步骤流程1. 环境配置2. 数据准备数据集下载数据存储结构&路径查看图片 3. 数据转换4. 自定义数据集&#xff08;Custom Dataset &#xff09;4.1 方法一&#xff1a;使用ImageFolder加载数据集信息查看张量转图片创建DataLoader 4.2 …

ChatGPT-4o抢先体验

速度很快&#xff0c;结果很智能&#xff0c;支持多模态输入输出&#xff0c;感兴趣联系作者

Unity开发Cosmos使用BNG Framework获取按键信息

Unity开发Cosmos使用BNG Framework获取按键信息 1、新建一个脚本&#xff0c;复制下面代码 using BNG;[Header("Input")]//[Tooltip("The key(s) to use to toggle locomotion type")]public List<ControllerBinding> locomotionToggleInput new …

SpringBoot+Vue实现前后端分离基本的环境搭建

目录 一、Vue项目的搭建 &#xff08;1&#xff09;基于vite创建vue项目 &#xff08;2&#xff09;引入elementplus &#xff08;3&#xff09;启动后端服务&#xff0c;并测试 二、SpringBoot项目的搭建 &#xff08;1&#xff09;通过idea创建SpringBoot项目 &#x…

每天五分钟深度学习PyTorch:Tensor张量的索引和切片

本文重点 有时候当我们拥有一个Tensor张量的时候,我们可能需要获取它某一维度的信息,那么此时我们就需要索引和切片的技术,它们可以帮助我们解决这些问题。 切片操作 a是四维的,然后默认是从第一维开始取,逗号表示取不同的维度 a[:2]表示第一维取0,1,后面三维取所有 …

一、大模型推理

https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://github.com/hiyouga/LLaMA-Factory/blob/main/examples/README_zh.md 安装 v7.1 https://github.com/hiyouga/LLaMA-Factory/releases/tag/v0.7.1 git clone --depth 1 https://github.com/hiyoug…

门面模式Api网关(SpringCloudGateway)

1. 前言 当前通过Eureka、Nacos解决了服务注册和服务发现问题&#xff0c;使用Spring Cloud LoadBalance解决了负载均衡的需求&#xff0c;同时借助OpenFeign实现了远程调用。然而&#xff0c;现有的微服务接口都直接对外暴露&#xff0c;容易被外部访问。为保障对外服务的安全…

问答机器人

怎样做自己的问答机器人&#xff1f; 根据我们提供的数据分析出问题的答案&#xff0c;我们并不需要训练自己的模型 微调模型 finetune&#xff0c;将语言模型调成另外的语言模型&#xff0c;更适合不同类型数据&#xff0c;运用finetune方法将模型变化 知识库模型 embedd…

alist配合onlyoffice 实现在线预览

alist配合onlyoffice 实现在线预览 文章目录 alist配合onlyoffice 实现在线预览一、安装onlyoffice二、增加view.html文件三、安装nginx&#xff0c;并增加conf配置文件四、alist预览配置增加 一、安装onlyoffice 我是采用docker安装&#xff0c;采用的版本是7.2&#xff0c; …

【因果推断python】16_工具变量2

目录 出生季度和教育对工资的影响 第一阶段 出生季度和教育对工资的影响 到目前为止&#xff0c;我们一直将这些工具视为一些神奇的变量 Z&#xff0c;它们具有仅通过干预变量影响结果的神奇特性。老实说&#xff0c;好的工具变量来之不易&#xff0c;我们不妨将它们视为奇迹…

Leetcode - 周赛400

目录 一&#xff0c;3168. 候诊室中的最少椅子数 二&#xff0c;3169. 无需开会的工作日 三&#xff0c;3170. 删除星号以后字典序最小的字符串 四&#xff0c;3171. 找到按位与最接近 K 的子数组 一&#xff0c;3168. 候诊室中的最少椅子数 本题是一道模拟题&#xff0c;直…

排序方法——《选择排序》

P. S.&#xff1a;以下代码均在VS2019环境下测试&#xff0c;不代表所有编译器均可通过。 P. S.&#xff1a;测试代码均未展示头文件stdio.h的声明&#xff0c;使用时请自行添加。 博主主页&#xff1a;Yan. yan.                        …

HCIP-Datacom-ARST自选题库_10_多种协议多选【24道题】

1.如图所示&#xff0c;PE1和PE2之间通过LoopbackO接口建立MP-BGP邻居关系&#xff0c;在配完成之后&#xff0c;发现CE1和CE2之间无法互相学习路由&#xff0c;下列哪些选项会造成该问题的出现? PE1或PE2未在BGP-VPNV4单播地址族视图使能邻居A PE1或PE2上的VPN实例参数配置错…

htb_solarlab

端口扫描 80,445 子域名扫描 木有 尝试使用smbclient连接445端口 Documents目录可查看 将Documents底下的文件下载到本地看看 xlsx文件里有一大串用户信息&#xff0c;包括username和password 先弄下来 不知道在哪登录&#xff0c;也没有子域名&#xff0c;于是返回进行全端…

第N4周:中文文本分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、预备知识 中文文本分类和英文文本分类都是文本分类&#xff0c;为什么要单独拎出来个中文文本分类呢&#xff1f; 在自然语言处理&#xff08;NLP&#x…

SickOS1.1 - Shellshock原理和利用过程精讲

SickOS1.1的另一种思路&#xff1b;用另一种方法打透这台机器 Nikto扫描 正常都是-h扫描&#xff1b;有代理就用-useproxy 指向的代理ip:端口 nikto -h 192.168.218.157 -useproxy 192.168.218.157:3128apache版本&#xff0c;有点低&#xff0c;现在都是2.4.54版本了&#x…

PDF批量加水印 与 去除水印实践

本文主要目标是尝试去除水印&#xff0c;但是为了准备测试数据&#xff0c;我们需要先准备好有水印的pdf测试文件。 注意&#xff1a;本文的去水印只针对文字悬浮图片悬浮两种特殊情况&#xff0c;即使是这两种情况也不代表一定都可以去除水印。 文章目录 批量添加透明图片水印…

OpenStreetMap部署(OSM)

参考&#xff1a;https://github.com/openstreetmap/openstreetmap-website/blob/master/DOCKER.md OpenStreeMap 部署 操作系统建议使用 Ubuntu 22 版本 安装 Docker # 更新软件包索引&#xff1a; sudo apt-get update # 允许APT使用HTTPS&#xff1a; sudo apt-get inst…