C++容易犯的九个陷阱(代码版本)

2024-02-06 20:28

本文主要是介绍C++容易犯的九个陷阱(代码版本),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

自己也算入行一年了,遇到不少坑,结合网上博客以及自己复现,总结有以下几个容易出错的点

目录

1、 unsigned不够理解

2、容器的size()返回的也是无符号整型

3、 容器删除元素迭代器失效

4、注释尽量用//而不是/**/

5、成员变量没有初始化行为需要手动初始化

6、浮点数判断是否相等

7、thread使用

8、注意操作符短路

9、对象切割


1、 unsigned不够理解

代码死循环

2、容器的size()返回的也是无符号整型

代码死循环

3、 容器删除元素迭代器失效

当从 std::vector 中移除一个元素时,所有该位置之后的元素都会向前移动,这意味着迭代器、引用和指向被移动元素的指针都会失效。

#include <iostream>
#include <vector>
using namespace std;void erase(std::vector<int>& vec, int a) {//for (auto iter = vec.begin(); iter != vec.end();) { // 这个正确//    if (*iter == a) {//        iter = vec.erase(iter);//    }//    else {//        ++iter;//    }//}for (auto iter = vec.begin(); iter != vec.end(); ++iter) {  // errorif (*iter == a) {vec.erase(iter); // 错误}}
}int main() {std::vector<int> vec;vec.push_back(1);vec.push_back(2);vec.push_back(3);vec.push_back(4);erase(vec, 2);erase(vec, 3);for (auto it = vec.begin(); it != vec.end(); it++) {cout << "cur:" << *it << endl;}return 0;
}

 4、注释尽量用//而不是/**/

关于中文乱码问题

5、成员变量没有初始化行为需要手动初始化

这样做的原因是为了确保数据的一致性和预期行为,避免出现未初始化的变量导致的不确定性和潜在的错误。

class MyClass {
public:MyClass() : myInt(0), myDouble(0.0) {} // 构造函数中初始化private:int myInt;    // 这些成员变量不会自动初始化double myDouble;
};

6、浮点数判断是否相等

#include <iostream>
#include <vector>
using namespace std;int main() {float f=0.2;if (f == 0.2) {cout << "1true";} // 错误用法if (abs(f - 0.2) < 0.00001) {cout << "2true";} // 正确用法return 0;
}

7、thread使用

记得要join


#include <iostream>
#include <vector>
#include <thread>
using namespace std;void func() {}
int main() {std::thread t(func);if (t.joinable()) {t.join(); // 或者t.detach(); }return 0;
}

8、注意操作符短路

||左边只要是true 那么右边的语句不执行了

&&左边只要是false 那么右边的语句就不执行了

bool HP() {std::cout << "我被执行HP方法" << std::endl;return true;
}
bool MP() {std::cout << "我被执行MP方法" << std::endl;return false;
}
int main() {if (HP() | MP()) {std::cout << "更新客户端" << std::endl;}return 0;}

 9、对象切割

当一个派生类对象被赋值给一个基类对象时,超出基类部分的成员变量会被“切割”掉,这会导致信息丢失。这个问题通常发生在使用值传递而非引用或指针传递派生类对象时。为了避免对象切割,应当使用指针或引用来处理多态。

 错误案例

#include <iostream>
using namespace std;class Base {
public:Base() { cout << "Base constructor\n"; }virtual void print() { cout << "Base class\n"; }virtual ~Base() { cout << "Base destructor\n"; }
};class Derived : public Base {
public:Derived() { cout << "Derived constructor\n"; }void print() override { cout << "Derived class\n"; }~Derived() override { cout << "Derived destructor\n"; }void specificFunction() { cout << "Specific function for Derived\n"; }
};void functionByValue(Base b) {cout << "************关注下面这一句****************" << endl;b.print(); // 这里会调用 Base 的 print,而不是 Derived 的cout << "****************************" << endl;
}int main() {Derived d;functionByValue(d); // 将 Derived 对象以值传递给函数return 0;
}

main 函数中,我们创建了一个 Derived 类的对象 d。当我们调用 functionByValue 并将 d 传递进去时,由于函数接受的是 Base 类型的值,因此 d 对象会被切割为 Base 类型。这意味着,函数内部的 b 对象只包含 Base 类的部分,Derived 类特有的成员和行为(如 specificFunction 方法和 Derived 类的 print 方法实现)都被丢弃了。因此,即使我们传递了一个 Derived 类型的对象,函数内部调用的 print 方法仍然是 Base 类的版本。 

正确案例:

修改为引用类型

void functionByReference(Base& b) {b.print(); // 这会调用正确的 print 方法,即 Derived 的 print
}int main() {Derived d;functionByReference(d); // 通过引用传递return 0;
}

 在这个修正后的版本中,我们通过引用传递 Derived 对象,因此 functionByReference 函数内部可以正确地调用 Derived 类的 print 方法,而不会发生对象切割。

 

总结了24个C++的大坑,看你能躲过几个?-CSDN博客

这篇关于C++容易犯的九个陷阱(代码版本)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/685438

相关文章

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

Ubuntu如何升级Python版本

《Ubuntu如何升级Python版本》Ubuntu22.04Docker中,安装Python3.11后,使用update-alternatives设置为默认版本,最后用python3-V验证... 目China编程录问题描述前提环境解决方法总结问题描述Ubuntu22.04系统自带python3.10,想升级

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W