本文主要是介绍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
类的Derived
类型的对象,函数内部调用的Base
类的版本。
正确案例:
修改为引用类型
void functionByReference(Base& b) {b.print(); // 这会调用正确的 print 方法,即 Derived 的 print
}int main() {Derived d;functionByReference(d); // 通过引用传递return 0;
}
在这个修正后的版本中,我们通过引用传递
Derived
对象,因此functionByReference
函数内部可以正确地调用Derived
类的
总结了24个C++的大坑,看你能躲过几个?-CSDN博客
这篇关于C++容易犯的九个陷阱(代码版本)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!