C++中常用的十个特性(c++基本特性)
liuian 2025-07-28 18:13 75 浏览
C++ 语言自1983年发布以来,经历了多个版本的迭代。随着C++11、C++14、C++17、C++20等新版本的发布,在原有的基础上引入了大量现代化的特性,使得C++的编程体验更加强大和简洁。今天,C++不仅仅是一个强大的系统级编程语言,也逐渐成为了一门高效、灵活的开发工具,广泛应用于各类应用开发中。
大致是在10年前开始将Modern 用到项目中,那时编译器版本是gcc4.9.2,支持了C++11,也就是从那个时候开始接触Modern C++,开始发现了新世界的大门,后面为了使用新特性,着手升级了两次,经历了gcc11.2以及现在的gcc14.2版本。
本文主要聊聊项目中常用常用到的十个特性,这些特性能够帮助开发者提升代码的可读性、可维护性和执行效率。
PS:本文旨在简单介绍,而不是深入各个特性的用法或者实现细节~
希望能够借助本文,能够帮您更好的了解Modern C++。
基于范围的带初始化器的for循环
C++20在基于范围的for循环基础上,引入了新的功能初始化器。此功能允许我们在for循环头内声明变量,从而简化代码并缩小范围。
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto size = numbers.size(); auto&& num : vec) {
std::cout << num << " " << size;
}这个特性特别适用于在循环中需要使用一个变量,但又希望将其作用域限制在循环内部,以防止在其他地方不小心使用该变量。
结构化绑定
C++17 引入的结构化绑定 (Structured bindings) 允许将元组、对 (pair) 和其他多元素对象解包为具名变量。这一特性极大地提升了代码的可读性。
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<std::string, int> ages = {{"A", 30}, {"B", 25}};
for (auto&& [name, age] : ages) {
std::cout << name << " is " << age << " years old." << std::endl;
}
return 0;
}结构化绑定在处理返回多个值的函数或遍历键值容器时特别有用。它使得解构和使用多个返回值变得更加简洁和直观。
inline变量
C++17 引入了inline变量,其语义与inline函数类似,只是它适用于变量。
最常见的是用于类内static变量的初始化:
class Test {
private:
inline static int value_ = 0; // 等同于类外执行 int Test::value = 0;
};与inline function一样,inline variable也允许在多个编译单元对同一个变量进行定义,并且在链接时只保留其中的一份作为该变量的定义。当然,同时在多个源文件中定义同一个inline变量必须保证它们的定义都相同,否则和inline函数一样,你没办法保证链接器最终采用的是哪个定义。
inline variable除了支持类内静态成员初始化外,也支持头文件中定义全局变量,这样不会违反ODR规则。
std::optional
C++17 引入的 std::optional 提供了一种更安全、更具表现力的方式来处理可选值。它是使用哨兵值或指针来表示可选数据的一个很好的替代方案。
struct Result {
char c;
uint32_t pos;
};
std::optional<Result> GetFirstUpper(const std::string &str) {
std::optional<Result> res;
for (int i = 0; i < str.size(); ++i) {
if (std::isupper(str[i])) {
res.c = elem;
res.pos = i;
return res;
}
}
return std::nullopt;
}std::optional 对于那些可能返回值也可能不返回值的函数特别有用,它在很多情况下消除了使用错误代码或异常的需求。
std::variant
std::variant,在 C++17 中引入,是一种类型安全的联合体,可以存储多个不同类型的值,但在任何时刻只能存储其中一种类型的值。与传统的 C 语言联合体不同,std::variant 提供了类型安全检查,避免了不小心访问错误类型的风险。
#include <variant>
#include <string>
#include <iostream>
int main() {
std::variant<int, float, std::string> data;
data = 10;
std::cout << std::get<int>(data) << std::endl;
data = "Hello";
std::cout << std::get<std::string>(data) << std::endl;
return 0;
}std::variant 在需要以类型安全的方式处理多种类型的场景中特别有用,例如解析不同的数据格式或实现状态机。它可以帮助你在处理多个不同类型的数据时,避免类型错误,并且使得代码更加清晰和易于维护。
std::visit
std::visit 是 C++17 引入的一个函数模板,用于访问 std::variant 中存储的值。它提供了一种类型安全的方式来处理 std::variant 中的不同类型,并通过访问器函数或 lambda 表达式来操作存储的值。
#include <variant>
#include <string>
#include <iostream>
structVisitor {
void operator()(int i) { std::cout << "Integer: " << i << std::endl; }
void operator()(float f) { std::cout << "Float: " << f << std::endl; }
void operator()(const std::string& s) { std::cout << "String: " << s << std::endl; }
};
int main() {
std::variant<int, float, std::string> data = 3.14f;
std::visit(Visitor{}, data);
return0;
}std::visit 在你需要根据 std::variant 中存储的类型执行不同操作时特别有用,它避免了类型检查和类型转换的繁琐过程。通过 std::visit,你可以直接根据 variant 中的实际类型来调用相应的操作,而无需手动进行类型识别或强制类型转换,从而保持代码的简洁和类型安全。
constexpr if
constexpr if 是 C++17 中引入的一个特性,它允许你在编译时根据条件选择性地包含或排除代码块。这使得模板编程更加灵活和高效。与常规的 if 语句不同,constexpr if 只有在条件为 true 时,相关代码才会被编译;如果条件为 false,编译器将会完全忽略对应的代码段,这样就避免了不必要的代码生成和运行时开销。
#include <type_traits>
#include <iostream>
template<typename T>
void PrintType(const T& value) {
if constexpr (std::is_integral_v<T>) {
std::cout << "Integral type: " << value << std::endl;
} elseifconstexpr (std::is_floating_point_v<T>) {
std::cout << "Floating-point type: " << value << std::endl;
} else {
std::cout << "Other type" << std::endl;
}
}
int main() {
PrintType(42);
PrintType(3.14);
PrintType("Hello");
return0;
}constexpr if 使你能够编写更灵活的模板,并在许多情况下避免使用 SFINAE,从而使代码更加简洁和可维护。通过在编译时做出条件判断,constexpr if 可以根据类型或其他条件选择性地编译不同的代码,而不需要依赖复杂的类型特化或 SFINAE 技巧。这不仅提升了代码的可读性,还减少了模板编程中的冗余,简化了错误处理和调试过程。
default & delete
在 C++11 中,**默认函数(Defaulted Functions)和删除函数(Deleted Functions)**是两个重要的特性,用来控制类的构造、拷贝、赋值等操作的行为。它们使得代码更加安全和可维护,避免了不必要的默认行为或不合法的操作。
#include <iostream>
classObj {
public:
Obj() = default; // 默认构造函数
Obj(const Obj&) = default; // 默认拷贝构造函数
Obj& operator=(const Obj&) = default; // 默认赋值运算符
~Obj() = default; // 默认析构函数
};
int main() {
Obj obj1; // 使用默认构造函数
Obj obj2 = obj1; // 使用默认拷贝构造函数
obj1 = obj2; // 使用默认赋值运算符
return0;
}nodiscard属性
[[nodiscard]] 属性是在 C++17 中引入的,它有助于防止开发者无意中忽略重要的返回值。当你将这个属性应用到一个函数或类型时,编译器会发出警告,提醒调用者不要忽视该函数的返回值。这个特性在返回错误码、状态信息或其他需要处理的结果时尤其有用。
#include <iostream>
[[nodiscard]] int GetArea(int width, int height) {
return width * height;
}
int main() {
GetArea(5, 10); // 这里会触发编译器警告,因为返回值被忽略了
int area = GetArea(5, 10); // 正确用法
std::cout << "Area: " << area << std::endl;
return 0;
}std::string_view
std::string_view 是在 C++17 中引入的一个新特性,它提供了一个对字符串的非拥有性视图。与 const std::string& 不同,std::string_view 不会复制字符串数据,而是直接引用原始数据。它是一个高效的替代方案,尤其在传递字符串时,可以避免不必要的内存分配和拷贝。
#include <iostream>
#include <string_view>
void Print(std::string_view str) {
std::cout << "String: " << str << std::endl;
}
int main() {
std::string_view view = "Hello, World!";
Print(view);
return 0;
}结语
这十个特性,在项目中用的算是很多了,当然了,还有lambda、auto等,在此就不再一一赘述了,通过此文,希望能帮助到您~
相关推荐
- 搭建一个20人的办公网络(适用于20多人的小型办公网络环境)
-
楼主有5台机上网,则需要一个8口路由器,组网方法如下:设备:1、8口路由器一台,其中8口为LAN(局域网)端口,一个WAN(广域网)端口,价格100--400元2、网线N米,这个你自己会看了:)...
- 笔记本电脑各种参数介绍(笔记本电脑各项参数新手普及知识)
-
1、CPU:这个主要取决于频率和二级缓存,频率越高、二级缓存越大,速度越快,现在的CPU有三级缓存、四级缓存等,都影响相应速度。2、内存:内存的存取速度取决于接口、颗粒数量多少与储存大小,一般来说,内...
- 汉字上面带拼音输入法下载(字上面带拼音的输入法是哪个)
-
使用手机上的拼音输入法打成汉字的方法如下:1.打开手机上的拼音输入法,在输入框中输入汉字的拼音,例如“nihao”。2.根据输入法提示的候选词,选择正确的汉字。例如,如果输入“nihao”,输...
- xpsp3安装版系统下载(windowsxpsp3安装教程)
-
xpsp3纯净版在采用微软封装部署技术的基础上,结合作者的实际工作经验,融合了许多实用的功能。它通过一键分区、一键装系统、自动装驱动、一键设定分辨率,一键填IP,一键Ghost备份(恢复)等一系列...
- 没有备份的手机数据怎么恢复
-
手机没有备份恢复数据方法如下1、使用数据线将手机与电脑连接好,在“我的电脑”中可以看到手机的盘符。 2、将手机开启USB调试模式。在手机设置中找到开发者选项,然后点击“开启USB调试模式”。 3、...
- 电脑怎么激活windows11专业版
-
win11专业版激活方法有多种,以下提供两种常用的激活方式:方法一:使用激活密钥激活。在win11桌面上右键点击“此电脑”,选择“属性”选项。进入属性页面后,点击“更改产品密钥或升级windows”。...
- 华为手机助手下载官网(华为手机助手app下载专区)
-
华为手机助手策略调整,已不支持从应用市场下载手机助手,目前华为手机助手是需要在电脑上下载或更新手机助手到最新版本,https://consumer.huawei.com/cn/support/his...
- 光纤线断了怎么接(宽带光纤线断了怎么接)
-
宽带光纤线断了可以重接,具体操作方法如下:1、光纤连接的时候要根据束管内,同色相连,同芯相连,按顺序进行连接,由大到小。一般有三种连接方法,分别是熔接、活动连接和机械连接。2、连接的时候要开剥光缆,抛...
- win7旗舰版和专业版区别(win7旗舰版跟专业版)
-
1、功能区别:Win7旗舰版比专业版多了三个功能,分别是Bitlocker、BitlockerToGo和多语言界面; 2、用途区别:旗舰版的功能是所有版本中最全最强大的,占用的系统资源,...
- 万能连接钥匙(万能wifi连接钥匙下载)
-
1、首先打开wifi万能钥匙软件,若手机没有开启WLAN,就根据软件提示打开WLAN开关;2、打开WLAN开关后,会显示附近的WiFi,如果知道密码,可点击相应WiFi后点击‘输入密码’连接;3、若不...
- 雨林木风音乐叫什么(雨林木风是啥)
-
雨林木风的创始人是陈年鑫先生。陈年鑫先生于1999年创立了雨林木风公司,其初衷是为满足中国市场对高品质、高性能电脑的需求。在陈年鑫先生的领导下,雨林木风以技术创新、产品质量和客户服务为核心价值,不断推...
- aics6序列号永久序列号(aics6破解序列号)
-
关于AICS6这个版本,虽然是比较久远的版本,但是在功能上也是十分全面和强大的,作为一名平面设计师的话,AICS6的现有的功能已经能够应付几乎所有的设计工作了……到底AICC2019的功能是不是...
- 手机可以装电脑系统吗(手机可以装电脑系统吗怎么装)
-
答题公式1:手机可以通过数据线或无线连接的方式给电脑装系统。手机安装系统需要一定的技巧和软件支持,一般需要通过数据线或无线连接的方式与电脑连接,并下载相应的软件和系统文件进行安装。对于大部分手机用户来...
- 一周热门
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
