C++编码规范(六)关于C++标准库STL在使用中的一些规范和建议
C++ 标准库STL是 C++ 编程语言的重要组成部分,为开发者提供了丰富的功能和工具,极大地提高了开发效率和代码的可移植性。
其主要包括:标准容器库,输入 / 输出流库,算法库,迭代器库,字符串库,数值计算库,异常处理库。
C++标准库STL在使用中,也有一些基本的使用规则和建议,列举如下:
1. 避免使用auto_ptr
在stl库中的std::auto_ptr具有一个隐式的所有权转移行为,转移所有权的行为通常不是我们期望的结果。对于必须转移所有权的场景,也不应该使用隐式转移的方式。所以,使用auto_ptr的代码需要额外谨慎,否则出现对空指针的访问。如下例子:
auto_ptr<T> p1(new T);
auto_ptr<T> p2 = p1;
//当执行完第2行语句后,p1已经不再指向第1行中分配的对象,而是变为NULL。
//正因为如此,auto_ptr不能被置于各种标准容器中。
2. 仅将scoped_ptr、shared_ptr和unique_ptr用于管理单个对象
boost::scoped_ptr、boost::shared_ptr、std::tr1::shared_ptr(在C++11标准中是std::shared_ptr)和std::unique_ptr(C++11标准)都是用于管理单一对象的智能指针。当这些智能指针在销毁所指向的对象时使用的都是delete而不是delete[],而使用delete删除数组是undefined行为,因此不能使用上述智能指针来管理数组。
当需要一个具有RAII特性的数组时,可以使用boost::scoped_array、boost::shared_array、std::vectorstd::tr1::shared_ptr或std::vectorstd::unique_ptr(C++11标准)代替。
shared_ptr是基于引用计数的智能指针,可以安全用于大部分场景中,更新引用计数时需要略微消耗一些性能,一般来说对性能不会有显著的影响。使用shared_ptr的另外一个需要注意的问题是不要产生循环引用,基于引用计数的智能指针当出现循环引用时会造成内存泄漏。当需要循环引用时,请使用weak_ptr智能指针。
3. 如果涉及循环引用,使用weak_ptr解开循环
当使用各种基于引用计数的shared_ptr时,会遇到循环引用的问题。为了解决循环引用导致的内存泄漏,需要引入weak_ptr。
#include <memory>
class TChild;
class TParent
{
public:void SetChild(std::shared_ptr<TChild> const& Child){Child_ = Child;}
private:
std::shared_ptr<TChild> Child_;
};class TChild
{
public:void SetParent(std::shared_ptr<TParent> const& Parent){Parent_ = Parent;}void UseParent(){//使用weak_ptr指向的对象之前通过lock()获得shared_ptr。std::shared_ptr<TParent> Parent = Parent_.lock();}
private:std::weak_ptr<TParent> Parent_;
};int main()
{std::shared_ptr<TParent> Parent = std::make_shared<TParent>();std::shared_ptr<TChild> Child = std::make_shared<TChild>();Parent->SetChild(Child);Child->SetParent(Parent);//到这里如果TChild中没有引入weak_ptr在处理,那么Parent和Child产生了循环引用,当Parent、Child超出作用域后将产生内存泄漏。
}
4. 使用make_shared代替new生成shared_ptr
在代码中,我们可以使用形如std::shared_ptr A(new T)的方式初始化shared_ptr。但是在涉及到shared_ptr的地方使用new涉及到3个潜在的风险。
- 一是容易出现访问悬空指针;
T* A = new T;
std::shared_ptr<T> B(A);
//当B超出作用域后:A指向的内存被释放,访问出错
A->xxxxx;
- 二是容易引起重复delete;
T* A = new T;
std::shared_ptr<T> B(A);
//在许多代码之后再次出现:
std::shared_ptr<T> C(A);
当使用一个原生指针初始化一个shared_ptr时,引用计数会被置为1,于是出现了两组独立的引用计数 ,当这两组引用计数到达0时都会引发销毁对象的操作,于是就会出现重复delete的问题;
- 三是可能出现内存泄漏的风险;
int func1();
void func2(std::shared_ptr<T> const& P1, int P2);
int main()
{func2(std::shared_ptr<T>(new T), func1());
}
如果在func1()中抛出了异常,将可能会造成new T泄漏;
5. 对于同一个对象一旦使用shared_ptr,后续就要处处使用shared_ptr
像前一个描述的,混用原生指针和shared_ptr容易导致悬空指针和重复释放的问题,所以同一对象的指针要统一用法,要么使用原生指针,要么使用shared_ptr,不要混用。
6. 对于返回自身的shared_ptr指针的对象,要从enable_shared_from_this类派生
对于需要使用shared_ptr管理的对象,当需要this指针时也需要使用对应的shared_ptr,但是如果直接使用shared_ptr(this)构造一个shared_ptr将会导致严重错误。为此,boost和stl都提供了对应的enable_shared_from_this类,该类提供了一个shared_from_this()函数返回this指针对应的shared_ptr。
例如:
class TClass : public std::enable_shared_from_this<TClass>
{
public:std::shared_ptr<TClass> GetSelf(){return shared_from_this();}std::shared_ptr<TClass const> GetSelf() const{return shared_from_this();}
};
7. 不要使用不同版本stl、boost等模板库编译的模块
模板库大量使用了内联函数,不同版本的模板库编译的模块对同一种数据类型的操作都已固化在该模块中。如果不同版本的模板库中同一种数据类型的结构或者内存布局不同,在一个模块中定义的对象被另外一个模块操作时可能会产生严重的错误。因为静态连接的模块常常不会划分出明确的接口,常常会相互访问其它模块中定义的对象。
8. 不要保存string::c_str()指针
C++标准中并未规定string::c_str()指针持久有效,因此特定stl实现完全可以在调用string::c_str()时返回一个临时存储区并很快释放。所以为了保证程序的移植性,一定不要保存string::c_str()的结果,而是在每次需要时直接调用。
std::string DemoStr = "demo";
const char* buf = DemoStr.c_str();
//在这里buf指向的位置有可能已经失效,会发生意想不到的情况
strncpy(info_buf,buf, INFOBUF_SIZE - 1);
9. 尽量使用stl、boost等知名模板库提供的容器,而不要自己实现容器
stl、boost等知名模板库已经提供较完善的功能,与其自行设计并维护一个不成熟且不稳定的库,不如掌握和使用标准库,标准库的使用经验在业界已有成熟的经验和使用技巧。
10. 尽量使用string代替char*
使用string代替char*有很多优势:
-
不用考虑结尾的’\0’;
-
可以直接使用+, =, ==等运算符以及其它字符串操作函数;
-
不需要考虑内存分配操作,避免了显式的new/delete,以及由此导致的错误;
当然也有一些例外:
- 当调用系统或者其它第三方库的API时,人家已经定义好的接口,让你只能使用char*。那么在调用接口之前都可以使用string,在调用接口时使用string::c_str()获得字符指针。
- 当在栈上分配字符数组当作缓冲区使用时,可以直接定义字符数组,不要使用string,也没有必要使用类似vector等容器。
相关文章:
C++编码规范(六)关于C++标准库STL在使用中的一些规范和建议
C 标准库STL是 C 编程语言的重要组成部分,为开发者提供了丰富的功能和工具,极大地提高了开发效率和代码的可移植性。 其主要包括:标准容器库,输入 / 输出流库,算法库,迭代器库,字符串库…...
两种文件类型(pdf/图片)打印A4半张纸方法
环境:windows10、Adobe Reader XI v11.0.23 Pdf: 1.把内容由横排变为纵排: 2.点击打印按钮: 3.选择打印页范围和多页: 4.内容打印在纸张上部 图片: 1.右键图片点击打印: 2.选择打印类型: 3.打印配置&am…...
Vue3状态管理: Pinia使用技巧与最佳实践
Vue3状态管理: Pinia使用技巧与最佳实践 随着Web应用复杂度的提升,前端状态管理变得愈发重要。而在Vue3中,Pinia作为一种全新的状态管理工具,为我们提供了更加灵活和强大的状态管理解决方案。本文将从Pinia的基本概念入手,深入探讨…...
stm32点灯 GPIO的输出模式
目录 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置( 默认不变)HSI 高速内部时钟8Mhz 5.项目配置 6.代码 延时1s循环LED亮灭 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置( 默认不变)…...
K8S运行时切换-从Docker到Containerd的切换实战
1. 切换的原因 性能提升:Containerd通过减少抽象层提升了整体性能。 安全性增强:它提供了更直接的系统调用,减少了潜在的安全风险。 简化架构:Containerd拥有更简洁的设计,使得维护和故障排除更为容易。 官方支持趋…...
腾讯会议win7二维码展示不出来
问题:win64更新后二维码展示不出来,手机等登陆都不行 安装所在位置创建文档命名TBSDEBUG并去掉后缀...
swift 专题三 swift 规范一
一、Swift编码命名规范 对类、结构体、枚举和协议等类型的命名应该采用大驼峰法,如 SplitViewController。 文件名采用大驼峰法,如BlockOperation.swift。 对于扩展文件,有时扩展定义在一个独立的文件中,用“原始类型名 扩展名…...
WPS计算机二级•幻灯片放映与会议
听说这是目录哦 放映PPT时常用的快捷技巧🥬设置放映模式🥕演讲备注的添加和隐藏🫚在PPT中插入附件并放映时打开🫛隐藏幻灯片 不被放映和打印🍄🟫演讲计时模式🥦能量站😚 放映PPT时…...
联想拯救者开机进入bios
如果你的联想拯救者(Lenovo Legion)笔记本电脑开机后直接进入 BIOS 设置界面,可能是以下原因之一导致的。以下是解决方法: 1. 检查启动顺序 进入 BIOS 后,找到 Boot(启动)选项卡。检查启动顺序…...
云原生周刊:K8s引领潮流
开源项目推荐 KWOK KWOK(Kubernetes WithOut Kubelet)是一个开源项目,旨在提供一个轻量级的 K8s 集群模拟环境,允许用户在不依赖真实节点的情况下,本地模拟整个 K8s 集群。它通过模拟 Kubelet 和其他集群组件的行为&…...
FBX SDK的使用:基础知识
Windows环境配置 FBX SDK安装后,目录下有三个文件夹: include 头文件lib 编译的二进制库,根据你项目的配置去包含相应的库samples 官方使用案列 动态链接 libfbxsdk.dll, libfbxsdk.lib是动态库,需要在配置属性->C/C->预…...
计算机网络笔记再战——理解几个经典的协议6——TCP与UDP
目录 先说端口号 TCP 使用序号保证顺序性和应答来保证有效性 超时重传机制 TCP窗口机制 UDP 路由协议 协议分类:IGP和EGP 几个经典的路由算法 RIP OSPF 链路状态数据库(LSDB) LSA(Link State Advertisement࿰…...
Android 单例模式:实现可复用数据存储
引言 在 Java 开发中,我们经常会遇到需要在整个应用程序中共享数据的场景。例如,配置信息、缓存数据等,这些数据需要在不同的模块或类中被访问和使用。为了确保数据的一致性和避免重复创建,我们可以使用单例模式来实现一个可复用的…...
【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制
【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制 一. 数据同步 在之前的学习中有了副本Replica的概念,解决了数据备份的问题。我们还需要面临一个设计难题即:如何处理分区中Leader与Follwer节点数据同步不匹配问题所带来的风险,这也是保证数据高可用的…...
【Linux】curl命令详解
【Linux】curl命令详解 【一】curl命令介绍【1】curl命令简介【2】curl命令的基本语法【3】常用的curl命令选项【4】常用的curl命令参数 【二】curl命令示例用法【1】下载文件【2】发送 POST 请求【3】发送请求时附加头部信息【4】请求方法【5】指定用户名和密码进行身份验证【…...
创建模态框和非模态框
主要的精简代码就这些 #include <QDialog>// 创建模态框 QDialog dialog(this); // 添加各种部件 // ... // 因为创建在栈上面,所以需要阻止程序继续运行 dialog.exec();// 非模态框 QDialog dialog new Dialog(this); // 添加各种部件 // ... dialog.show(…...
电商用户画像数据可视化分析
电商用户画像数据可视化分析 作者:i阿极 作者简介:Python领域新星作者、多项比赛获奖者:博主个人首页 😊😊😊如果觉得文章不错或能帮助到你学习,可以点赞👍收藏📁评论&am…...
Vue3.5常用特性整理
Vue3.5 发布已近半年,抽空整理下常用的新增/改动特性 响应式 Props 解构 Vue3.5 中 Props 正式支持解构了,并添加了响应式跟踪 设置默认值 使用 JavaScript 原生的默认值语法声明 props 默认值 以前 const props withDefaults(defineProps<{ co…...
Android Studio:Application 和 Activity的区别
Application 和 Activity 是 Android 中非常重要的两个组件,它们分别负责不同的生命周期管理和应用的不同层次的操作。 Application 是应用级别的生命周期管理,它在整个应用运行时只有一个实例,负责应用的全局初始化和资源管理。Activity 是…...
深入解析“Self-Contained”——从技术到日常的全方位应用
深入解析“Self-Contained”——从技术到日常的全方位应用 一、引言 在阅读技术文档、编程指南或产品说明时,你可能经常看到 self-contained 这个短语。例如: Our end goal is a self-contained project containing two parts. https://howistart.org/p…...
2024年12月 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试
202412 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试 一、单选题(共25题,共50分) 第 1 题 点击下列哪个按钮,可以将红框处的程序放大?( ) A. B. C. D. 标…...
llama.cpp GGML Quantization Type
llama.cpp GGML Quantization Type 1. GGML Quantization Type2. static const struct ggml_type_traits type_traits[GGML_TYPE_COUNT]3. Q#_K_M and Q#_KReferences 什么神仙妖魔,不过是他们禁锢异族命运的枷锁! GGUF https://huggingface.co/docs/hu…...
【深度学习框架】MXNet(Apache MXNet)
MXNet(Apache MXNet)是一个 高性能、可扩展 的 开源深度学习框架,支持 多种编程语言(如 Python、R、Scala、C 和 Julia),并能在 CPU、GPU 以及分布式集群 上高效运行。MXNet 是亚马逊 AWS 官方支持的深度学…...
游戏引擎学习第87天
当直接使用内存时,可能会发生一些奇怪的事情 在直接操作内存时,一些意外的情况可能会发生。由于内存实际上只是一个大块的空间,开发者可以完全控制它,而不像高级语言那样必须遵守许多规则,因此很容易发生错误。在一个…...
【物联网】ARM核常用指令(详解):数据传送、计算、位运算、比较、跳转、内存访问、CPSR/SPSR
文章目录 指令格式(重点)1. 立即数2. 寄存器位移 一、数据传送指令1. MOV指令2. MVN指令3. LDR指令 二、数据计算指令1. ADD指令1. SUB指令1. MUL指令 三、位运算指令1. AND指令2. ORR指令3. EOR指令4. BIC指令 四、比较指令五、跳转指令1. B/BL指令2. l…...
Qt展厅播放器/多媒体播放器/中控播放器/帧同步播放器/硬解播放器/监控播放器
一、前言说明 音视频开发除了应用在安防监控、视频网站、各种流媒体app开发之外,还有一个小众的市场,那就是多媒体展厅场景,这个场景目前处于垄断地位的软件是HirenderS3,做的非常早而且非常全面,都是通用的需求&…...
VSCode源码分析参考资料
VSCode Architecture Analysis - Electron Project Cross-Platform Best Practices 中文版 VSCode 架构分析 - Electron 项目跨平台最佳实践 Sihan Li博客上的vscode源码分析系列:分析了微服务架构、事件体系、资源管理、配置系统等 文召博客上的vscode 源码解析…...
html中的表格属性以及合并操作
表格用table定义,标签标题用caption标签定义;用tr定义表格的若干行;用td定义若干个单元格;(当单元格是表头时,用th标签定义)(th标签会略粗于td标签) table的整体外观取决…...
html的字符实体和颜色表示
在HTML中,颜色可以通过以下几种方式表示,以下是具体的示例: 1. 十六进制颜色代码 十六进制颜色代码以#开头,后面跟随6个字符,每两个字符分别表示红色、绿色和蓝色的强度。例如: • #FF0000:纯红…...
unordered_map/set的哈希封装
【C笔记】unordered_map/set的哈希封装 🔥个人主页:大白的编程日记 🔥专栏:C笔记 文章目录 【C笔记】unordered_map/set的哈希封装前言一. 源码及框架分析二.迭代器三.operator[]四.使用哈希表封装unordered_map/set后言 前言 哈…...
