Cplusplus 简明教程
Advanced C++ Concepts
C 是现代编程的基本语言之一。它已从基本 C 发展为现代编程中非常强大的工具。C 的版本从 C 98 开始,现已升级至 C 20 。在 C 11 更新后,所有现代更新被统称为现代 C。这些新模型有大量新功能,使该语言更友好和具有更好的功能。其中一些新概念已成为其他新语言的部分,如 Ethereum 、 Ruby 、 Python 和 Javascript ,而随着这些概念在 C++ 中的引入,现在的编程变得更高效。
我们将在详细了解以下不同的高级 C++ 主题:
随 C 20 版本,还提供了其他功能,这些功能稍微更高级,将在本帖的后面部分讨论。上述功能也是非常高级的概念,但本帖所提供的说明足以使读者深入了解 MODERN C LANGUAGE 。
RAII (Resource Aquisition is Initialization)
Resource Acquisition is Initialization (通常用其缩写 RAII 指代)是用于执行 memory management 的 C 技术。虽然它与 C 的关联通常是学习它的原因,但 RAII 的范围超越了语言限制的障碍。
简单地提出一个定义,RAII 表示以构造函数的形式向对象分配内存,然后使用 destructor 释放已分配的内存。因此,它构成了我们在过去主题中讨论过的 OOP concepts 的一部分。
现在,你一定很好奇 RAII 实际上解决了哪些问题?RAII 有很多种作用,其中一些如下:
本部分中已讨论了其中一些主题,而新的概念将在本帖的后面部分讨论。
现在,在编程中 resource 实际上是什么,特别是在面向对象的编程(OOPS)中?
资源是一个实体,可以在程序或一系列程序的编译或执行中进行要求。资源的示例包括 Stack 、 Heap 、 Memory 、 Files 、 Sockets (在套接字编程中)、 Locks and Semaphores 等。这些资源对程序的顺利运行至关重要。这些资源通过程序通过请求获取,例如用于获取互斥锁的 mutex() 方法调用。
在使用 C 的经典编程中,我们使用 new() 和 delete() 的概念来创建实体,然后释放内存。这个传统概念虽然在 C 这样的面向对象语言中仍然可以接受,但是,不鼓励使用。在 C 中,RAII 的概念使得在作用域内分配和释放资源变得容易。
新的数量的任期就是对象的任期,并且构造函数可以为对象创建和分配内存,而析构函数可用于仅仅在自动完成之后释放内存。这使得 C++ 成为一种非常高效且用户友好的语言。我们用一个简单的示例来理解这一点。
Example
#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;
}
Wild Pointers in C++
如果指针随机指向内存中的任何地址,则该指针称为野指针。当指针在程序中声明时,但未初始化为指向地址值时,就会发生这种情况。野指针不同于普通指针,即它们还存储内存地址,但指向未分配的内存或已被释放的数据值。
这些指针可能导致 memory leak ,这将在本文的后面部分讨论。
Example
#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
Null Pointers in C++
在 C++ 的早期版本中, NULL 将定义为无意义的元素,它不指向任何内存。允许将 NULL 转换为 int 或类似数据类型,但对于函数的 overloading ,NULL 指针会引发错误。
自从 C++ 11 出现以来,NULL 已重新定义为 nullptr ,它是一种特殊数据类型,只能用作指向内存中不可用地址的指针。
因此,它可以在重新定义指针变量时充当指向任何位置的指针。与 NULL 不同,它不能隐式转换为整数类型,例如 int 或 char ,也不能与整数类型进行比较。因此,它根本解决了 NULL 的问题。
顺便提一下,在 C++ 的较新版本中可以比较空指针,因此可以理解指针可以与 bool 数据类型进行比较。
Memory Leakage in C++
内存泄漏是许多计算设备中的一个主要问题,因为编译器在程序中可用的 stack 和 heap 内存是有限的且非常昂贵的。当声明新对象、使用新对象并且未从内存中清除新对象时,就会发生内存泄漏。如果程序员忘记使用 delete operation ,或错误地使用它,则可能会发生这种情况。
内存泄漏有很大的缺点,因为随着每个传入进程的请求,空间会呈指数级增加,并且必须为新进程分配新的内存空间,而不是清除不需要的内存。
给定的程序说明了如何使用 C++ 中的程序中发生内存泄漏。
Example
#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() 对象的内存释放掉来避免。以下程序说明了如何避免内存泄漏。
Smart Pointers in C++
随着 RAII 和 OOP 概念在 C 中的引入, wrapper classes 也已在 C 中引入。其中一个包装器类是智能指针,它有助于确保没有内存泄漏和错误实例。
Lambda Expression in C++
自 C 11 以来,允许在 C 中使用 lambda 表达式来解析 inline functions ,该表达式用于较小的代码行,而无需为函数提供名称和作用域。
Syntax
[ capture clause ] (parameters) -> return-type{
definition of method
}
在此,返回类型由编译器本身解析,无需指定函数的 return type 。但是,对于复杂语句,指定了返回类型以使编译器正常运行。
可以以下列方式捕获外部变量:
-
Capture by reference
-
Capture by value
-
同时捕获(混合捕获)
用于捕获变量的语法如下 -
-
[&]:引用捕获所有外部变量
-
[=]:值捕获所有外部变量
-
[a,&b]:值捕获 a 并引用捕获 b
Example
#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