C++中常用的十个特性(c++基本特性)
liuian 2025-07-28 18:13 97 浏览
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等,在此就不再一一赘述了,通过此文,希望能帮助到您~
相关推荐
- 苹果笔记本怎么下载windows系统
-
方法一:使用BootCamp方法二:使用虚拟机方法三:使用Wine简介BootCamp是苹果电脑自带的一个软件,可以帮助用户在Mac上安装Windows操作系统。虚拟机则是运行在Mac上的一个软件...
- 华硕电脑激活码(华硕电脑windows激活码在哪里)
-
你所说的应该是系统激活密钥吧华硕OEM密钥就行!HomePremium(家庭高级版):27GBM-Y4QQC-JKHXW-D9W83-FJQKDUltimate(旗舰版):6K2KY-BF...
- wifi如何防止别人蹭网(wifi如何防止别人蹭网呢)
-
防止WIFI被蹭网的方法1、家庭的wifi信号,一般是通过设置无线路由器发射出来。在设置无线路由器时,一定要注意设置无线密码的安全强度。最好含有大小写字母加数字的组合,不要设置连续数字,比如“1234...
- 无线ap安装示意图(无线ap如何安装方法)
-
商用无线ap安装完成后连接ap应用添加wifi网络信号将无线网卡插入电脑USBWindows7/8系统下,网卡安装成功后直接进行软件安装...2.继续安装类型,推荐保持默认选择,点击“下一步”继续安装...
- miui官网开发版下载(小米miui开发版下载)
-
你好,miui12开发版下载方式如下1打开浏览器,登录小米Rom官网,2进去之后搜索自己的手机型号,3点击进入就可以看到所有发布过的miui版本4点击想要的12版本下载即可。现在的MIUI开发版需要申...
-
- 惠普台式机进入bios设置u盘启动
-
设置u盘启动的步骤如下:1、首先,将u盘插入hp台式机的USB接口处。2、开机快速断续的按F10键进入BIOS设置界面。3、将光标移到【BootDevicePriority】选项按回车键进入。4、选择【HDDGroupBootPr...
-
2026-01-15 00:37 liuian
- 云手机免费版无限挂机怎么用
-
1、登陆后,如果需要挂网页游戏,点击服务器的左下角,找到IE浏览器,然后打开网页游戏,登陆你的账号就行了,不要关闭IE浏览器,你的网页游戏就会24小时挂在云服务器上面。2、如果想要挂机,打开IE浏览器...
- 上海最近3天疫情情况(上海近几天的新冠疫情情况)
-
根据国家卫健委的每天疫情通报及上海市的疫情通报,上海没有一个区属中高风险地区,所以从上海任何一个区返乡都不需要隔离14天。上海这么大的城市,每天人来人往的Ill流不息,能继续做到区级地区没有中高级风险...
- windows media player怎么下载
-
方法如下:在安装WMP11时只是把C:\DocumentsandSettings\AllUsers\ApplicationData\WindowsGenuineAdvantage\data...
- during(during用法)
-
during用来表示一段时间,其意义大致相当于in的用法。一般来说,凡是能用in的地方,也可以用during.例如:Hecametoseemeduringmyabsence.Don’t...
- 深圳电脑城在哪里(深圳电脑卖场)
-
龙岗:世纪电脑城,平湖电脑城,京科电脑城坪山新区:坪山电脑城龙华:观澜电脑城,大浪电脑城,宏华电脑城,龙华电子城宝安区:赛格电子城,宝安电子城,丰明电脑城,沙井电子城龙岗中心区那边有两个电子城,...
- 电脑上怎么清理c盘垃圾(电脑里怎么清理c盘的东西)
-
C:\ProgramFiles\WindowsApps(隐藏文件夹)。打开“此电脑”,点击“查看”,勾选“隐藏的项目”,即可查看隐藏文件。为保证文件安全,此文件夹需要获取权限才能操作。获取方式...
- 手机哪个杀毒软件最好用
-
杀毒软件我有用过好几种用过之觉得体验感及安全性来说人喜欢推荐腾讯手机管家功能比较全面监控流量、查杀病毒、保护隐私等等界面也比较漂亮重点还要定期扫描同时也要轻易点开别人发链接之类软件有提示危险绝对要点开...
-
- 笔记本电脑怎样截图(苹果笔记本电脑怎样截图)
-
方法/步骤1第一个办法自然是我们最常见最简单的,使用“PrintScreen”键截图了。点击“PrintScreen”键,我们就可以直接截取全部屏幕,找个对话框或者文字区域粘贴就好了。我截的图是这样的2Windows系统都自带有截图工具,我...
-
2026-01-14 22:37 liuian
- vaio笔记本u盘启动(hipaa笔记本u盘启动)
-
可能是u盘启动快捷键没有使用正确。因为笔记本型号不同,所以BIOS会有所不同,并且进入bios的启动快捷键也会不同。而索尼笔记本开机需要按F2键进入bios设置中。 2、在bios中没有正确设置u盘...
- 一周热门
-
-
飞牛OS入门安装遇到问题,如何解决?
-
如何在 iPhone 和 Android 上恢复已删除的抖音消息
-
Boost高性能并发无锁队列指南:boost::lockfree::queue
-
大模型手册: 保姆级用CherryStudio知识库
-
用什么工具在Win中查看8G大的log文件?
-
如何在 Windows 10 或 11 上通过命令行安装 Node.js 和 NPM
-
威联通NAS安装阿里云盘WebDAV服务并添加到Infuse
-
Trae IDE 如何与 GitHub 无缝对接?
-
idea插件之maven search(工欲善其事,必先利其器)
-
如何修改图片拍摄日期?快速修改图片拍摄日期的6种方法
-
- 最近发表
- 标签列表
-
- 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)
