360网站建设服务器,建设英文网站,企业微信小程序定制,绍兴网站制作方案定制原文链接欢迎回到 C - 现代 C | Microsoft Learn
这里先是讲了现代c的优势#xff0c;其相对于其他编程语言有快速、高效。 相对于其他语言#xff0c;该语言更加灵活#xff0c;跨平台#xff08;硬件平台#xff09;性也很强#xff0c;可以直接访问硬件#xff0c;虽…原文链接欢迎回到 C - 现代 C | Microsoft Learn
这里先是讲了现代c的优势其相对于其他编程语言有快速、高效。 相对于其他语言该语言更加灵活跨平台硬件平台性也很强可以直接访问硬件虽然现在编程千千万但是访问硬件的语言这点可以干掉几乎90%的编程语言其应用广泛。但是现在很多硬件的编程还是使用c语言最近也有慢慢被c替代的趋势。现代 C 代码更加简单、安全、美观而且速度仍像以往一样快速。 接下来从几个方面来大体概括了一下现代C的优势。
资源和智能指针
原始的c语言容易出现的内存泄露问题这里可以通过RAIIResource Acquisition Is Initialization的原则进行规避这个规则要求资源堆内存、文件句柄、套接字等应由对象“拥有”。 该对象在其构造函数中创建或接收新分配的资源并在其析构函数中将此资源删除。 RAII 原则可确保当所属对象超出范围时所有资源都能正确返回到操作系统。
为了让我们更方便的遵循这个原则编程c标准库提供了三种智能指针类型std::unique_ptr、std::shared_ptr 和 std::weak_ptr。
智能指针可以自己管理对象的资源当对象被释放的时候对应的资源也会被释放这些智能指针都是通过模板Template来实现的。我们只需要把我们需要的对象通过std::unique_ptrint[] data;
unique_ptr来指向对象实例化的时候通过make_unique来实现data std::make_uniqueint[](size)
这样实例化的对象我们就直接遵循了RAII原则。对象的管理交给智能指针这个只能指针也是一个模板类其内部的实现就是管理对象的生存周期以及资管的管理。比如unique_ptr 存储指向拥有的对象或数组的指针。 此对象/数组仅由 unique_ptr 拥有。 unique_ptr 被销毁后此对象/数组也将被销毁。shared_ptr 类描述使用引用计数来管理资源的对象。 shared_ptr 对象有效保留一个指向其拥有的资源的指针或保留一个 null 指针。 资源可由多个 shared_ptr 对象拥有当拥有特定资源的最后一个 shared_ptr 对象被销毁后资源将释放。
std::string 和 std::string_view
这两个类为了消除字符串编程的过程中遇到的一些问题在编程的过程中难免会引用字符串。
C语言中对于字符串的使用容易出现bug尤其各种字符格式转换的过程c直接实现了自己的库 std::string 和 std::wstring几乎可以消除与 C 样式字符串关联的所有错误。并且同时提供搜索、追加和在前面追加等操作。在 C17 中可以使用 std::string_view以便提高性能。
这里可以理解到c通过自己实现的标准库帮我们造了一个轮子。c把之前c语言编程中遇到的一些问题做成了标准库避免那些问题的实现我们通过新类直接引用即可。
std::vector 和其他标准库容器
从里面来看这是一个向量向量在编程中也属于一种容器其他还有map等用来管理我们的一些数据类型比如字符串或者整形浮点型等。容器就是装东西的在编程语言中是用来装数据的不同的数据类型都可以装到容器中包括自己定义的类我们自己定义的类也可以理解为一种数据类型在程序的世界中一起资源皆是数据类型都是数字最终都对应010101针对这些容器c都实现了自己的标准库java等其他语言也对这些容器做了标准库这些库在使用的过程中很多优势尤其是其丰富的功能以及久经考验的算法。比如查找排序等避免自己再次造轮子除非你的算法由于当前的api如果那样的话c肯定会收录你的。 标准库算法
这里讲到了C里面的一些标准库算法包含我们常见的如搜索、排序、筛选和随机化等这些分类在不断增长。 数学库的内容很广泛。 在 C17 及更高版本中提供了许多算法的并行版本。
以下是一些重要示例 for_each默认遍历算法以及基于范围的 for 循环。 transform用于对容器元素进行非就地修改 find_if默认搜索算法。 sort、lower_bound 和其他默认的排序和搜索算法。
auto comp [](const widget w1, const widget w2) { return w1.weight() w2.weight(); }
sort( v.begin(), v.end(), comp );
auto i lower_bound( v.begin(), v.end(), widget{0}, comp );
这个代码段里面用到了lambda表达式一个简单的引用示例。 用 auto 替代显式类型名称 auto是一个非常智能的类型指定关键字它可以自己推导出数据类型避免我们定义的时候出现错误。可以代指任意类型现在很多语言在定义的数据的时候都支持了任意类型比如kotlin中使用var代指定义数据类型不用指定具体的类型可以在运行的时候进行决定。python直接连var这种指定都省略了。 基于范围的 for 循环
在java早就使用了这种编程方式很多现代语言也采用了这种方式传统的方式写起来真的很麻烦限制很大如下
std::vectorint v {1,2,3};
// C-style
for(int i 0; i v.size(); i)
{ std::cout v[i];
}
但是现代语言的写法直接如下
// Modern C:
for(auto num : v)
{
std::cout num;
}
直接给出需要遍历的对象甚至类型都不必指定直接auto然后我们可以轻易遍历引用其中的数据省去很多无用的代码。 用 constexpr 表达式替代宏 constexpr也是现代c的产物原始定义编译时的常量采用#define宏定义的方式但是这种方式容易出错而且无法调试所以出现了constexpr在预编译的时候就进行处理。 在现代 C 中应优先使用 constexpr 变量定义编译时常量
其平替效果如下
#define SIZE 10 // C-style constexpr int size 10; // modern C
与 const 一样它可以应用于变量如果任何代码试图 modify修改该值将引发编译器错误。 与 const 不同constexpr 也可以应用于函数和类 constructor构造函数。 constexpr 指示值或返回值是 constant常数如果可能将在编译时进行计算。 统一初始化
现代C支持任意类型的括号初始化当我们需要初始化数组矢量等容器时其优势明显编译器可以自己推断每个元素的类型比如下面的示例
#include vector
struct S { std::string name; float num; S(std::string s, float f) : name(s), num(f) {} };
int main() { // C-style initialization std::vectorS v; S s1(Norah, 2.7); S s2(Frank, 3.5); S s3(Jeri, 85.9); v.push_back(s1); v.push_back(s2); v.push_back(s3); // Modern C: std::vectorS v2 {s1, s2, s3}; // or... std::vectorS v3{ {Norah, 2.7}, {Frank, 3.5}, {Jeri, 85.9} };
}
这个示例中我们的类C中结构体和类class等效S有一个自己的构造
在v3实例中我们的vector通过指定了S类型所以编译器可以自己推导类型实例所以我们可以根据S的构造运用{}直接传参构成实例这时候编译器自己帮我们推导出S类型的实例push到vector实例v3中。省去了v2的meige