C++使用中需要避免的10个常见错误

简介: C++使用中需要避免的10个常见错误

简介

在编写C++代码时,我们常常会犯一些常见的错误。以下是一些常见的错误及其解决方案。

一、不使用命名空间

  1. 命名冲突可能引起编译错误
  2. 名称空间可以提高代码可读性和维护性
#include <iostream>
using namespace std;  // 不使用命名空间将无法使用cout

int main()
{
   
    int count = 0;
    cout << "Hello World!" << endl;  // 使用命名空间来输出
    return 0;
}

在上面的代码中使用了标准库的命名空间std,以便我们可以直接使用cout,而不是std::cout来输出Hello World。

二、不正确使用头文件

  1. 库和用户头文件的区别
  2. 头文件中定义变量的正确方式
// user.h 头文件
#ifndef USER_H
#define USER_H

class User
{
   
    int m_age;  // 私有成员变量

public:
    User(int age);
    void setAge(int age);
    int getAge() const;
};

#endif  // USER_H

// user.cpp 源文件
#include "user.h"

User::User(int age)
{
   
    m_age = age;
}

void User::setAge(int age)
{
   
    m_age = age;
}

int User::getAge() const
{
   
    return m_age;
}

// main.cpp 源文件
#include "user.h"

int main()
{
   
    User user(18);  // 创建一个User对象
    user.setAge(20);  // 设置用户年龄
    return 0;
}

在上面的代码中首先在user.h头文件中定义了一个User类,并在user.cpp源文件中实现了这个类。最后在main.cpp中,我们使用#include指令来包含user.h头文件,并使用User类。

三、没有检查数组越界

  1. 数组越界可能引起不可预测的错误
  2. 使用数组时应注意数组下标是否超出范围
#include <iostream>
using namespace std;

int main()
{
   
    int arr[10] = {
   1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    for(int i = 0; i < 11; i++)  // 数组下标超出范围
    {
   
        cout << arr[i] << endl;
    }
    return 0;
}

在上面的代码中尝试使用一个长度为10的数组来遍历所有11个元素,这会导致数组下标超出范围,从而导致不可预测的行为。

四、忘记释放动态分配的内存

  1. 内存泄漏会造成程序运行时间变长和在长时间运行后程序崩溃
  2. 释放内存时应检查指针是否为空,以防空指针
#include <iostream>
using namespace std;

int main()
{
   
    int* p = new int[10];  // 分配动态内存
    p[0] = 1;
    delete[] p;
    // 以下是常见的错误方式
    delete[] p;  // 重复释放内存
    p = NULL;  // 释放后悬挂指针
    return 0;
}

在上面的代码中首先使用new运算符分配动态内存,然后使用delete[]运算符释放内存。需要注意的是,一定要在释放内存后将指针置为NULL。

五、不使用const关键字

  1. 利用const关键字可以防止变量被错误修改
  2. 使用const可以提高代码的可读性和安全性
#include <iostream>
using namespace std;

int main()
{
   
    const int count = 10;
    count = 20;  // 试图修改const变量会导致编译错误
    return 0;
}

在上面的代码中首先定义了一个const变量count,并试图在后面将它修改为20。由于count是一个const变量,这会导致编译错误。

六、指针误用

  1. 指针未初始化就被使用
  2. 删除了常量指针
  3. 指针运算时未考虑指针类型和指针长度

示例代码:

#include <iostream>
using namespace std;

int main()
{
   
    int* ptr;  // 指针未初始化
    *ptr = 1;  // 试图使用未初始化的指针

    const int* constPtr = new int(2);  // 常量指针
    delete constPtr;  // 删除常量指针会导致编译错误

    int arr[5] = {
   1, 2, 3, 4, 5};
    char* cp = reinterpret_cast<char*>(arr);  // 未考虑指针类型和长度
    cp++;  // 指针偏移了4个字节
    int* ip = reinterpret_cast<int*>(cp);
    cout << *ip << endl;  // 输出的结果是2,而不是1
    return 0;
}

在上面的代码中展示了三种指针误用的情况。在第一种情况中,我们定义了一个指针但未初始化,在后续使用时就会产生不确定行为。第二种情况中,我们定义了一个常量指针并尝试删除它,这会导致编译错误。在第三种情况中,我们将一个整型数组的地址赋给了一个字符型指针,并进行偏移操作,但由于未考虑指针类型和长度,导致输出结果不是期望的结果。

七、类型强制转换错误

  1. 可能会引起编译警告或错误
  2. 强制转换时应考虑类型兼容性和数据精度是否会发生变化

示例代码:

#include <iostream>
using namespace std;

int main()
{
   
    int a = 10, b = 3;
    float c = static_cast<float>(a) / b;  // 静态类型转换
    cout << c << endl;

    double d = 3.14;
    int* p = reinterpret_cast<int*>(&d);  // 使用reinterpret_cast进行强制类型转换
    *p = 100;
    cout << d << endl;  // d的值已经被改变了,出现不可预测的行为

    return 0;
}

在上面的代码中使用static_cast进行类型转换,用于计算答案。在第二个例子中,我们使用reinterpret_cast转换浮点型变量d的地址并修改它。注意,这种转换方法只能用于某些特定的场景,如使用位操作来解析一个整体。它可能引起不可预测的行为。

八、浮点数比较不准确

  1. 浮点数计算时存在精度误差
  2. 比较浮点数应使用特定的比较函数

示例代码:

#include <iostream>
#include <cmath>
using namespace std;

int main()
{
   
    double a = 0.1 + 0.2;
    double b = 0.3;
    if(abs(a - b) < 1e-9)  // 比较浮点数需考虑精度误差
    {
   
        cout << "a and b are the same" << endl;
    }

    return 0;
}

在上面的代码中使用了浮点数计算,但由于浮点数的精度误差,a和b可能不完全相等。因此,在比较两个浮点数时,我们应该使用特定的比较函数,例如abs(a-b) < 1e-9。

九、忘记判断函数返回值

  1. 忘记判断函数返回值可能导致程序出现异常行为
  2. 一定要对函数返回值进行判断,以保证程序的正确性

示例代码:

#include <iostream>
#include <fstream>
using namespace std;

int main()
{
   
    ifstream file("test.txt");
    if(!file)  // 未判断文件打开是否成功
    {
   
        cout << "Failed to open file" << endl;
    }
    else
    {
   
        // do something
        file.close();
    }

    return 0;
}

在上面的代码中使用了ifstream类来读取文件,但我们忘记判断文件打开是否成功。如果该文件不存在,则打开文件时可能会出现异常行为。

十、不使用引用传参

  1. 引用传参可以节省内存空间和时间开销
  2. 对于大量数据的函数传参,引用传参可以提高程序的效率

示例代码:

#include <iostream>
#include <string>
using namespace std;

void changeVaue(int& a)
{
   
    a = 100;
}

int main()
{
   
    int a = 10;
    changeVaue(a);  // 引用传参
    cout << a << endl;  // 输出100
    return 0;
}

在上面的代码中定义了一个使用引用传参的函数来改变变量a的值。由于引用传参不需要复制大量数据,因此可以提高程序的效率。

目录
相关文章
|
编译器 Android开发 C++
工作中遇到的C++语言基础和常见错误
## C++历史及标准 这里简单列一下```C++```发展进程中的几次重大事件以及我常使用的典型特性,各个标准支持的具体细节可参阅ISO标准文档。 - ```C With Classes```:支持C++基础语言特性,包括多态、异常处理、模板、命名空间等 - ```C++98```:STL、RTTI、模板、异常处理及其它标准库实现 - ```C++03```:修复C++98中的缺
1086 0
|
存储 C++
【C++初级】static用法总结、问题探讨及常见错误排查
static的基本用法: static的作用主要有两种第一个作用是限定作用域;第二个作用是保持变量内容持久化; 一、c语言中static的用法:   1、全局静态变量:     用法:在全局变量前加上关键字static,全局变量就定义成一个全局静态变量。
1601 0
|
C++
C++常见错误坑洞
指针没初始化就使用*解引用运算符; 连续delete释放new指针; 使用delete 是否常规普通变量内存; 地址直接复制给制作   
602 0
|
分布式计算 Java Hadoop
hadoop-HA集群搭建,启动DataNode,检测启动状态,执行HDFS命令,启动YARN,HDFS权限配置,C++客户端编程,常见错误
本篇博文为整理网络上Hadoop-HA搭建后出来的博客,参考网址为:http://blog.chinaunix.net/uid-196700-id-5751309.html 3. 部署 3.1. 机器列表 共5台机器(zookeeper部署在这5台机器上),部署如下表所示: NameNode JournalNode DataNode ZooKeeper 192.168.106
7951 0
|
C++ 编译器
2014秋C++第5周项目1参考-见识初学者常见错误
课程主页在http://blog.csdn.net/sxhelijian/article/details/39152703,实践要求见http://blog.csdn.net/sxhelijian/article/details/39493833。 课程资源在云学堂“贺老师课堂”同步展示,使用的帐号请到课程主页中查看。   【项目1】下面是最经典和最简单的C++程序。在ideone.com中运
1125 0
|
Linux
让你提前认识软件开发(51):VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改
第3部分 软件研发工作总结 VC++集成开发环境中Linux下Pclint工程的配置方法及常见错误修改   【文章摘要】         Pclint是一种C/C++软件代码静态分析工具。
1597 0
|
编译器 C++
我的 VC++ 常见错误问题解决办法
1.没有解决的外部定义错误xyView.obj : error LNK2001: unresolved external symbol "public: __thiscall CMyOCRInfo::CMyOCRInfo(void)" (??0CMyOCRInfo@@QAE@XZ)可能是由于构造方法没有实现代码 2.
1057 0
|
Windows 数据安全/隐私保护 C++