C++编码规范(六)关于C++标准库STL在使用中的一些规范和建议

news2025/2/6 5:21:33

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等容器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2293611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两种文件类型(pdf/图片)打印A4半张纸方法

环境:windows10、Adobe Reader XI v11.0.23 Pdf: 1.把内容由横排变为纵排&#xff1a; 2.点击打印按钮&#xff1a; 3.选择打印页范围和多页&#xff1a; 4.内容打印在纸张上部 图片&#xff1a; 1.右键图片点击打印&#xff1a; 2.选择打印类型&#xff1a; 3.打印配置&am…

Vue3状态管理: Pinia使用技巧与最佳实践

Vue3状态管理: Pinia使用技巧与最佳实践 随着Web应用复杂度的提升&#xff0c;前端状态管理变得愈发重要。而在Vue3中&#xff0c;Pinia作为一种全新的状态管理工具&#xff0c;为我们提供了更加灵活和强大的状态管理解决方案。本文将从Pinia的基本概念入手&#xff0c;深入探讨…

stm32点灯 GPIO的输出模式

目录 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置&#xff08; 默认不变&#xff09;HSI 高速内部时钟8Mhz 5.项目配置 6.代码 延时1s循环LED亮灭 1.选择RCC时钟 2.SYS 选择调试模式 SW 3.GPIO 配置 4.时钟树配置&#xff08; 默认不变&#xff09…

腾讯会议win7二维码展示不出来

问题&#xff1a;win64更新后二维码展示不出来&#xff0c;手机等登陆都不行 安装所在位置创建文档命名TBSDEBUG并去掉后缀

swift 专题三 swift 规范一

一、Swift编码命名规范 对类、结构体、枚举和协议等类型的命名应该采用大驼峰法&#xff0c;如 SplitViewController。 文件名采用大驼峰法&#xff0c;如BlockOperation.swift。 对于扩展文件&#xff0c;有时扩展定义在一个独立的文件中&#xff0c;用“原始类型名 扩展名…

WPS计算机二级•幻灯片放映与会议

听说这是目录哦 放映PPT时常用的快捷技巧&#x1f96c;设置放映模式&#x1f955;演讲备注的添加和隐藏&#x1fada;在PPT中插入附件并放映时打开&#x1fadb;隐藏幻灯片 不被放映和打印&#x1f344;‍&#x1f7eb;演讲计时模式&#x1f966;能量站&#x1f61a; 放映PPT时…

FBX SDK的使用:基础知识

Windows环境配置 FBX SDK安装后&#xff0c;目录下有三个文件夹&#xff1a; include 头文件lib 编译的二进制库&#xff0c;根据你项目的配置去包含相应的库samples 官方使用案列 动态链接 libfbxsdk.dll, libfbxsdk.lib是动态库&#xff0c;需要在配置属性->C/C->预…

计算机网络笔记再战——理解几个经典的协议6——TCP与UDP

目录 先说端口号 TCP 使用序号保证顺序性和应答来保证有效性 超时重传机制 TCP窗口机制 UDP 路由协议 协议分类&#xff1a;IGP和EGP 几个经典的路由算法 RIP OSPF 链路状态数据库&#xff08;LSDB&#xff09; LSA&#xff08;Link State Advertisement&#xff0…

【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制

【技海登峰】Kafka漫谈系列(二)Kafka高可用副本的数据同步与选主机制 一. 数据同步 在之前的学习中有了副本Replica的概念,解决了数据备份的问题。我们还需要面临一个设计难题即:如何处理分区中Leader与Follwer节点数据同步不匹配问题所带来的风险,这也是保证数据高可用的…

电商用户画像数据可视化分析

电商用户画像数据可视化分析 作者&#xff1a;i阿极 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f4c1;评论&am…

Vue3.5常用特性整理

Vue3.5 发布已近半年&#xff0c;抽空整理下常用的新增/改动特性 响应式 Props 解构 Vue3.5 中 Props 正式支持解构了&#xff0c;并添加了响应式跟踪 设置默认值 使用 JavaScript 原生的默认值语法声明 props 默认值 以前 const props withDefaults(defineProps<{ co…

2024年12月 Scratch 图形化(一级)真题解析 中国电子学会全国青少年软件编程等级考试

202412 Scratch 图形化&#xff08;一级&#xff09;真题解析 中国电子学会全国青少年软件编程等级考试 一、单选题(共25题&#xff0c;共50分) 第 1 题 点击下列哪个按钮&#xff0c;可以将红框处的程序放大&#xff1f;&#xff08; &#xff09; A. B. C. D. 标…

游戏引擎学习第87天

当直接使用内存时&#xff0c;可能会发生一些奇怪的事情 在直接操作内存时&#xff0c;一些意外的情况可能会发生。由于内存实际上只是一个大块的空间&#xff0c;开发者可以完全控制它&#xff0c;而不像高级语言那样必须遵守许多规则&#xff0c;因此很容易发生错误。在一个…

【物联网】ARM核常用指令(详解):数据传送、计算、位运算、比较、跳转、内存访问、CPSR/SPSR

文章目录 指令格式&#xff08;重点&#xff09;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开发之外&#xff0c;还有一个小众的市场&#xff0c;那就是多媒体展厅场景&#xff0c;这个场景目前处于垄断地位的软件是HirenderS3&#xff0c;做的非常早而且非常全面&#xff0c;都是通用的需求&…

html中的表格属性以及合并操作

表格用table定义&#xff0c;标签标题用caption标签定义&#xff1b;用tr定义表格的若干行&#xff1b;用td定义若干个单元格&#xff1b;&#xff08;当单元格是表头时&#xff0c;用th标签定义&#xff09;&#xff08;th标签会略粗于td标签&#xff09; table的整体外观取决…

html的字符实体和颜色表示

在HTML中&#xff0c;颜色可以通过以下几种方式表示&#xff0c;以下是具体的示例&#xff1a; 1. 十六进制颜色代码 十六进制颜色代码以#开头&#xff0c;后面跟随6个字符&#xff0c;每两个字符分别表示红色、绿色和蓝色的强度。例如&#xff1a; • #FF0000&#xff1a;纯红…

unordered_map/set的哈希封装

【C笔记】unordered_map/set的哈希封装 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】unordered_map/set的哈希封装前言一. 源码及框架分析二.迭代器三.operator[]四.使用哈希表封装unordered_map/set后言 前言 哈…

idea中git的简单使用

提交&#xff0c;推送直接合并 合到哪个分支就到先切到哪个分支

Fastdds学习分享_xtpes_发布订阅模式及rpc模式

在之前的博客中我们介绍了dds的大致功能&#xff0c;与组成结构。本篇博文主要介绍的是xtypes.分为理论和实际运用两部分.理论主要用于梳理hzy大佬的知识&#xff0c;对于某些一带而过的部分作出更为详细的阐释&#xff0c;并在之后通过实际案例便于理解。案例分为普通发布订阅…