自己也算入行一年了,遇到不少坑,结合网上博客以及自己复现,总结有以下几个容易出错的点
目录
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) { // error
if (*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
类的