- C++ 基础
- C++ 首页
- C++ 概述
- C++ 环境设置
- C++ 基本语法
- C++ 注释
- C++ Hello World
- C++ 省略命名空间
- C++ 常量/字面量
- C++ 关键字
- C++ 标识符
- C++ 数据类型
- C++ 数值数据类型
- C++ 字符数据类型
- C++ 布尔数据类型
- C++ 变量类型
- C++ 变量作用域
- C++ 多个变量
- C++ 基本输入/输出
- C++ 修饰符类型
- C++ 存储类
- C++ 运算符
- C++ 数字
- C++ 枚举
- C++ 引用
- C++ 日期和时间
- C++ 控制语句
- C++ 决策
- C++ if 语句
- C++ if else 语句
- C++ 嵌套 if 语句
- C++ switch 语句
- C++ 嵌套 switch 语句
- C++ 循环类型
- C++ while 循环
- C++ for 循环
- C++ do while 循环
- C++ foreach 循环
- C++ 嵌套循环
- C++ break 语句
- C++ continue 语句
- C++ goto 语句
- C++ 构造函数
- C++ 构造函数和析构函数
- C++ 复制构造函数
高级 C++ 概念
C++ 是现代编程的基础语言之一。它从基本的 C 语言演变而来,成为现代编程中非常强大的工具。C++ 的版本从 C++ 98 开始,现在已经发展到 C++ 20。在 C++ 11 更新之后,所有现代更新都被统称为现代 C++。这些新模型具有广泛的新功能,使该语言更易于用户使用,并具有更好的功能。其中一些新概念已经是其他新语言的一部分,例如 以太坊、Ruby、Python 和 Javascript,随着这些概念在 C++ 中的引入,如今的编程效率更高。
以下是我们将详细了解的不同高级 C++ 主题的列表:
随着C++ 20版本的发布,还提供了其他功能,这些功能稍微高级一些,将在本文的后面部分介绍。上面提到的功能也是非常高级的概念,但是本文提供的解释足以让读者深入研究现代 C++ 语言。
RAII(资源获取即初始化)
资源获取即初始化,通常用其缩写 RAII 指代,是一种用于内存管理的 C++ 技术。虽然它通常与 C++ 相关联,这就是为什么它被研究的原因,但 RAII 的范围超出了语言限制的障碍。
简单地说,RAII 意味着以构造函数的形式将内存分配给对象,然后使用析构函数释放分配的内存。因此,它构成了OOP 概念的一部分,这在之前的主题中已经介绍过。
现在,您一定很好奇 RAII 到底解决了哪些问题?RAII 以多种方式工作,其中一些是:
这些主题中的一些已经在本文的前面部分讨论过,一些新概念将在本文的后面部分讨论。
现在,在编程中,尤其是在面向对象编程方面,资源究竟是什么?
资源是在编译或执行程序或一系列程序期间可能需要的实体。资源的示例包括栈、堆、内存、文件、套接字(在套接字编程中)、锁和信号量等。这些资源对于程序的顺利运行至关重要。程序通过请求获取这些资源,例如,对于互斥锁,使用 mutex() 方法调用来获取。
在使用 C 的经典编程中,我们使用 new() 和 delete() 的概念来创建实体,然后释放内存。这种传统概念在 C++ 等 OOP 语言中仍然可以接受,但是不鼓励使用。在 C++ 中,RAII 的概念使得在作用域内轻松分配和释放资源成为可能。
新数量的有效期是对象的有效期,构造函数可以创建和分配内存给对象,而析构函数可以用来在完成后自动释放内存。这使得 C++ 成为一种非常高效且用户友好的语言。让我们通过一个简单的例子来理解这一点。
示例
#include <bits/stdc++.h> using namespace std; mutex m; void bad() { m.lock(); // acquire the mutex f(); // if f() throws an exception, the mutex is never released if (!everything_ok()) return; // early return, the mutex is never released m.unlock(); // if bad() reaches this statement, the mutex is released } void good(){ lock_guard<mutex> lk(m); // RAII class: mutex acquisition is initialization f(); // if f() throws an exception, the mutex is released if (!everything_ok()) return; // early return, the mutex is released } int main(){ good(); bad(); return 0; }
C++ 中的野指针
如果指针随机指向内存中的任何地址,则该指针称为野指针。当在程序中声明指针但未将其初始化为指向地址值时,就会发生这种情况。野指针与普通指针不同,即它们也存储内存地址,但指向未分配的内存或已释放的数据值。
这些指针可能导致内存泄漏,这将在本文的后面部分讨论。
示例
#include <bits/stdc++.h> using namespace std; int main() { int *ptr; //this pointer has been declared but not initialized //hence, it is a wild pointer cout<<*ptr<<endl; int a=11; ptr=&a; cout<<*ptr<<endl<<ptr<<endl; //once a value is declared, it becomes a normal pointer *ptr=10; cout<<*ptr<<endl<<ptr; return 0; }
输出
-660944088 11 0x7ffcfb77825c 10 0x7ffcfb77825c
C++ 中的空指针
在早期版本的 C++ 中,NULL 将被定义为指向任何内存的 void 元素。允许将 NULL 转换为int 或类似的数据类型,但在函数重载的情况下,空指针会引发错误。
自从C++ 11出现以来,NULL 已重新定义为nullptr,这是一种特殊的数据类型,只能用作指针来指向内存中不可用的地址。
因此,它可以在重新定义指针变量时充当指向任何位置的指针。与 NULL 不同,它不能隐式转换为整数类型(如int或char),也不能与整数类型进行比较。因此,它解决了 NULL 的固有问题。
顺便说一句,在新版本的 C++ 中,空指针之间可以进行比较,因此可以理解指针可以与bool数据类型进行比较。
示例
#include <bits/stdc++.h> using namespace std; int main() { //int ptr=nullptr; //this throws compiler error as it is not comparable to int //run the above line for illustration int *ptr=nullptr; if(ptr==nullptr) cout<<"true"; else cout<<"false"; return 0; }
输出
true
C++ 中的内存泄漏
内存泄漏是许多计算设备中的一个主要问题,因为编译器在程序中可用的栈和堆内存是有限的且非常昂贵。当声明新对象、使用新对象但未清除内存中的新对象时,就会发生内存泄漏。如果程序员忘记使用delete 操作或错误地使用它,就会发生这种情况。
内存泄漏有很大的缺点,因为空间随着每个传入的进程请求呈指数增长,新的进程必须分配新的内存空间,而不是清除不需要的内存。
给定的程序演示了如何在使用 C++ 的程序中发生内存泄漏。
示例
#include <bits/stdc++.h> using namespace std; void leak_func(){ int* p = new int(10); //using new() to declare a new object //no delete() operation return; } int main(){ leak_func(); return 0; }
可以通过释放最初分配给new()对象的内存来避免这种情况。下面的程序说明了如何避免内存泄漏。
示例
#include <bits/stdc++.h> using namespace std; void leak_func(){ int* p = new int(10); //using new() to declare a new object delete(p); return; } int main(){ leak_func(); return 0; }
C++中的智能指针
随着C++中RAII和OOP概念的引入,包装类也已在C++中引入。这些包装类之一是智能指针,它有助于确保没有内存泄漏和错误的实例。
示例
#include <bits/stdc++.h> using namespace std; int main() { //int ptr=nullptr; //this throws compiler error as it is not comparable to int int *ptr=nullptr; if(ptr==nullptr) cout<<"true"; else cout<<"false"; return 0; }
输出
true
C++中的Lambda表达式
从C++ 11开始,允许在C++中使用lambda表达式来解决内联函数,这些函数用于少量代码行,无需为函数命名和指定作用域。
语法
[ capture clause ] (parameters) -> return-type{ definition of method }
在这里,返回类型由编译器本身解析,无需指定函数的返回类型。但是,对于复杂的语句,需要指定返回类型才能使编译器正常运行。
可以按以下方式捕获外部变量:
- 按引用捕获
- 按值捕获
- 同时捕获(混合捕获)
用于捕获变量的语法如下:
- [&]:按引用捕获所有外部变量
- [=]:按值捕获所有外部变量
- [a, &b]:按值捕获a,按引用捕获b
示例
#include <bits/stdc++.h> using namespace std; void printvector(vector<int> &v){ // lambda expression to print vector for_each(v.begin(), v.end(), [](int i){ std::cout << i << " "; }); cout << endl; } int main(){ vector<int> v; v.push_back(10); v.push_back(11); v.push_back(12); printvector(v); return 0; }
输出
10 11 12