【C/C++】详解 assert() 断言(什么是assert? assert有什么作用?) 异常处理

C++异常处理详解 看这一篇就够了

什么是异常? 异常就是在程序执行过程中发生的一些不正常的情况,比如除以0、数组越界等。这些情况会让程序无法继续正常执行,所以我们需要一种机制来处理这些异常。

如何处理异常? 在C++中,我们使用try和catch来处理异常。

try块:把可能产生异常的代码放在try块中。 catch块:如果try块中的代码产生了异常,那么程序会跳转到catch块中执行。 举个例子 假设我们有一个简单的程序,它会让用户输入一个数字,然后计算这个数字的倒数。如果用户输入了0,那么程序就会产生一个异常,因为0没有倒数。

#include <iostream>  
  
int main() {  
    int number;  
    std::cout << "请输入一个数字:";  
    std::cin >> number;  
    try {  
        if (number == 0) {  
            throw "不能除以0!"; // 抛出一个异常  
        }  
        std::cout << "数字的倒数是:" << 1.0 / number << std::endl;  
    } catch (const char* msg) { // 捕获异常  
        std::cout << "发生异常:" << msg << std::endl;  
    }  
  
    return 0;  
}

在这个例子中,如果用户输入了0,程序就会抛出一个异常("不能除以0!"),然后跳转到catch块中执行,输出"发生异常:不能除以0!"。如果用户输入了一个非0的数字,程序就会正常计算并输出这个数字的倒数。

总结 异常处理就是用来处理程序中可能发生的不正常情况的一种机制。在C++中,我们使用try和catch来处理异常。把可能产生异常的代码放在try块中,然后在catch块中处理这些异常。

5 条评论

  • @ 2024-7-24 22:53:59

    C++中的assert是一个宏,用于在运行时检查某个条件是否为真。如果条件为假,则assert会输出错误信息并终止程序执行。这是开发过程中发现逻辑错误和假设错误的一种重要调试手段。以下是关于C++ assert的详细教程:

    一、assert的基本用法 包含头文件: 在使用assert之前,需要包含头文件(或在旧代码中可能是<assert.h>)。 cpp

    #include <cassert>
    

    基本语法: assert宏的基本语法是assert(expression);,其中expression是需要检查的条件表达式。 cpp

    assert(condition);
    

    如果condition为true,则assert不执行任何操作;如果为false,则输出错误信息并终止程序。

    错误信息: 默认情况下,当assert失败时,会输出包含文件名、行号和失败的条件的错误消息。但是,直接控制输出的错误消息内容是不可能的,因为assert是通过宏实现的。 二、assert的使用场景 检查参数合法性: 在函数入口处使用assert来检查传入参数的合法性。 cpp

    void myFunction(int param) {  
        assert(param > 0); // 确保param大于0  
        // 函数体...  
    }
    

    检测不应发生的情况: 使用assert来检测那些理论上不应该发生的情况,如内部逻辑错误。 cpp

    int result = computeValue();  
    assert(result != -1); // 假设-1表示一个不应该发生的错误状态
    

    单元测试: 在单元测试中,使用assert来验证代码行为是否符合预期。 三、assert的优缺点 优点:

    快速定位错误:assert可以在条件不满足时立即终止程序,帮助开发者快速定位问题。 易于使用:语法简单,不需要额外的错误处理代码。 缺点:

    影响性能:虽然影响通常很小,但在性能敏感的应用中可能需要考虑。 不适用于生产环境:assert主要用于开发阶段,发布的产品代码中通常会被禁用。 四、禁用assert 在发布版本中,通常会禁用assert以避免性能影响。这可以通过定义宏NDEBUG来实现。

    cpp

    #define NDEBUG  
    #include <cassert>  
      
    // 此时,所有的assert调用都将无效  
    void myFunction() {  
        assert(false); // 这将不会执行任何操作  
    }
    

    五、assert与异常处理的比较 assert和异常处理(try-catch)是两种不同的错误处理机制。

    assert用于检测不应该发生的情况,条件不满足时会终止程序。 异常处理用于处理程序运行时可能遇到的预期错误,提供了一种恢复和继续执行的机制。 六、注意事项 每个assert只检验一个条件,以便于在断言失败时快速定位问题。 assert中不应使用改变环境的语句,如自增、自减操作,以避免在禁用assert时导致代码行为不一致。 在使用assert时,应确保它不会掩盖真正的错误或导致程序在禁用时行为异常。 通过以上教程,你应该对C++中的assert宏有了更深入的了解,并能够在开发过程中有效地使用它来帮助调试和定位问题。

    • @ 2024-7-24 22:50:51
      1. 异常处理的进一步理解 异常传递:当try块中的代码抛出一个异常时,如果当前函数中没有匹配的catch块,这个异常会沿着函数调用栈向上传递,直到找到能够处理它的catch块为止。如果最终没有找到匹配的catch块,程序会调用std::terminate()函数终止执行。 多个catch块:一个try块后面可以跟多个catch块,每个catch块用于捕获并处理不同类型的异常。当异常发生时,程序会按顺序检查每个catch块,直到找到匹配的类型为止。 捕获所有异常:如果你想要捕获所有类型的异常,可以使用省略号(...)作为catch块的参数。这被称为“通用捕获”。
      2. 异常处理的示例扩展 下面是一个扩展的示例,展示了如何使用多个catch块和通用捕获来处理不同类型的异常。

      cpp

      #include <iostream>  
      #include <string>  
      using namespace std;  
        
      int main() {  
          try {  
              // 假设这里有一些复杂的计算,可能会抛出不同类型的异常  
              throw 100; // 抛出一个整数类型的异常  
              // throw "出错了!"; // 也可以抛出一个字符串类型的异常  
              // throw 3.14; // 或者抛出一个浮点数类型的异常  
          } catch (int e) {  
              cout << "捕获到整数类型的异常:" << e << endl;  
          } catch (const string& e) {  
              cout << "捕获到字符串类型的异常:" << e << endl;  
          } catch (double e) {  
              cout << "捕获到浮点数类型的异常:" << e << endl;  
          } catch (...) {  
              cout << "捕获到未知类型的异常" << endl;  
          }  
        
          return 0;  
      }
      

      在这个示例中,我们抛出了不同类型的异常,并使用了多个catch块来捕获和处理它们。注意,由于我们一次只能抛出一个异常,所以上面的代码中只有第一个throw语句会生效。你可以通过取消注释不同的throw语句来测试不同类型的异常处理。

      1. 异常处理的最佳实践 避免在析构函数中抛出异常:析构函数的主要目的是清理资源,如果在析构函数中抛出异常,可能会导致程序更加混乱。 谨慎使用异常规格:在C++11及以后的版本中,函数声明中的异常规格(exception specifications)已经被弃用,并建议使用noexcept关键字来替代。然而,对于小学生来说,这部分内容可能过于复杂,可以暂时忽略。 自定义异常类:虽然面向对象的概念不在本次教程的范围内,但值得一提的是,在实际开发中,为了更好地表示和处理异常,通常会定义自己的异常类。这些类通常会从std::exception类派生,并提供额外的信息和方法。不过,对于初学者来说,可以先从使用标准异常类开始。 合理使用异常:异常处理虽然强大,但也不是万能的。在性能敏感的代码区域,或者当错误处理逻辑与正常逻辑紧密耦合时,可能需要考虑其他错误处理机制(如错误码)。
      • @ 2024-7-24 22:49:29

        C++异常处理入门教程 什么是异常? 想象一下,你在做数学题时,突然遇到了一个除数为0的情况,这时你就不能继续按照正常的除法规则来计算了,因为除数为0在数学上是不允许的。在编程中,这种情况就像是一个“异常”,它打断了程序的正常执行流程。

        为什么要处理异常? 处理异常是为了让程序在遇到问题时能够给出一些提示或者采取一些补救措施,而不是直接崩溃或者停止运行。这样,即使程序遇到了错误,我们也能知道错在哪里,并尝试去修复它。

        C++中如何处理异常? 在C++中,处理异常主要用到三个关键字:try、catch和throw。

        throw 当你发现程序中出现了无法处理的情况时,可以使用throw关键字来抛出一个异常。抛出的东西可以是一个数字、一个字符串或者任何你想要的东西,但通常我们会抛出一个错误消息或者一个特定的错误代码。

        示例:

        cpp

        if (除数 == 0) {  
            throw "不能除以0!";  
        }
        

        try 你可能会问,既然抛出了异常,那谁来处理它呢?这时候就需要用到try块了。我们把可能会抛出异常的代码放在try块里面。如果try块里面的代码抛出了异常,程序就会停止执行try块里的剩余代码,并去寻找能够处理这个异常的catch块。

        示例:

        cpp

        try {  
            // 这里是可能会抛出异常的代码  
            if (除数 == 0) {  
                throw "不能除以0!";  
            }  
            // 其他代码...  
        }
        

        catch catch块就是用来捕获并处理异常的。每个catch块后面都会跟着一个异常类型(或者省略类型来捕获所有异常),用来指定这个catch块能够处理哪种类型的异常。当try块抛出了异常时,程序会去寻找与之匹配的catch块,并执行该块中的代码。

        示例:

        cpp

        try {  
            // ...(可能会抛出异常的代码)  
        } catch (const char* msg) {  
            // 这里处理捕获到的异常  
            cout << "捕获到异常:" << msg << endl;  
        }
        

        注意:在这个例子中,我们使用const char*类型来捕获异常,因为我们抛出的是一个字符串。但是,你也可以抛出其他类型的对象,并在catch块中使用相应的类型来捕获它们。

        完整示例 下面是一个完整的示例,展示了如何在C++中使用try、catch和throw来处理除数为0的异常:

        cpp

        #include <iostream>  
        using namespace std;  
          
        int main() {  
            int 被除数 = 10;  
            int 除数 = 0;  
          
            try {  
                if (除数 == 0) {  
                    throw "不能除以0!";  
                }  
                cout << "结果是:" << 被除数 / 除数 << endl;  
            } catch (const char* msg) {  
                cout << "捕获到异常:" << msg << endl;  
            }  
          
            return 0;  
        }
        

        在这个示例中,当除数等于0时,程序会抛出一个字符串类型的异常,并在catch块中捕获并处理这个异常,输出“捕获到异常:不能除以0!”。

        • @ 2024-7-24 22:46:36

          C++异常处理教程 一、异常的基本概念 异常是在程序执行过程中发生的不正常情况,它打断了正常的程序流程。异常处理是一种编程机制,允许程序在遇到异常时能够优雅地处理,而不是简单地崩溃。

          二、异常处理的关键字 C++异常处理主要涉及到三个关键字:try、catch和throw。

          throw:用于抛出异常。当程序遇到无法处理的错误时,可以使用throw关键字抛出一个异常。抛出的异常可以是C++中的任何类型,包括内置类型(如int、float等)、指针类型、字符串类型或自定义类型。 try:try块用于标识可能引发异常的代码区域。如果try块中的代码抛出了异常,程序将停止执行try块中的剩余代码,并查找与之匹配的catch块来处理异常。 catch:catch块用于捕获并处理异常。每个catch块后面都跟着一个异常声明,用于指定该catch块能够捕获的异常类型。如果抛出的异常与某个catch块后面的异常声明匹配,那么程序将执行该catch块中的代码。 三、异常处理的语法 异常处理的基本语法如下:

          cpp

          try {  
              // 可能引发异常的代码  
          } catch (异常类型1 变量名1) {  
              // 处理异常类型1的代码  
          } catch (异常类型2 变量名2) {  
              // 处理异常类型2的代码  
          } // 可以有多个catch块来处理不同类型的异常  
          catch (...) {  
              // 处理所有未捕获的异常  
          }
          

          如果try块中的代码抛出了异常,程序将按顺序查找catch块,直到找到与抛出的异常类型匹配的catch块。 如果抛出的异常类型与所有catch块都不匹配,且存在catch (...)块,则执行该块中的代码。catch (...)块用于捕获所有未明确指定的异常类型。 如果抛出的异常没有任何catch块能够捕获,则程序将调用std::terminate()函数终止执行。 四、异常处理的示例 以下是一个简单的异常处理示例:

          cpp

          #include <iostream>  
          using namespace std;  
            
          int main() {  
              int a = 10, b = 0;  
              try {  
                  if (b == 0) {  
                      throw "除数不能为0!"; // 抛出一个字符串类型的异常  
                  }  
                  cout << "结果是:" << a / b << endl;  
              } catch (const char* msg) {  
                  // 捕获并处理字符串类型的异常  
                  cerr << "异常:" << msg << endl;  
              }  
              return 0;  
          }
          

          在这个示例中,如果b等于0,程序将抛出一个字符串类型的异常。由于try块后面跟着一个能够捕获字符串类型异常的catch块,因此程序将执行该catch块中的代码,输出异常信息。

          五、异常处理的注意事项 避免在析构函数中抛出异常:析构函数的主要作用是释放资源,如果在析构函数中抛出异常,可能会导致资源泄露或程序崩溃。 异常规格说明(已弃用):在早期的C++标准中,可以使用异常规格说明来限制函数可能抛出的异常类型。然而,这个功能在C++11及以后的版本中已被弃用,因为它限制了程序的灵活性且难以正确使用。 自定义异常类:为了更好地表示和处理异常,可以定义自己的异常类。通常,自定义异常类会从std::exception类派生,并重载what()方法以提供异常信息。 异常的安全传递:在抛出和捕获异常时,应确保异常对象能够安全地传递。特别是当异常对象包含指针或引用时,需要特别注意对象的生命周期和内存管理。 异常的性能考虑:虽然异常处理能够提高程序的健壮性和可维护性,但它也可能对性能产生一定影响。因此,在性能敏感的代码区域中应谨慎使用异常处理。 通过以上教程,你应该对C++中的异常处理有了更深入的理解。在实际编程中,合理地使用异常处理机制可以使你的程序更加健壮和易于维护。

          • @ 2024-7-24 22:44:50

            C++异常处理教程(面向小学生) 什么是异常? 异常就是在程序运行时发生的一些“不正常”的事情,这些事情可能会让程序崩溃或者无法继续运行。比如,你尝试除以0,或者数组索引超出了范围。

            为什么要处理异常? 因为异常可能会导致程序崩溃,而我们希望程序在遇到这些问题时能够给出友好的提示,而不是直接崩溃。所以,我们需要学会如何处理这些异常。

            如何处理异常? 在C++中,我们使用try和catch来处理异常。

            try块:把可能会引发异常的代码放在try块中。 catch块:如果try块中的代码引发了异常,那么程序会跳转到catch块中,我们可以在这里处理异常。 举个例子 假设我们有一个程序,它会让用户输入一个数字,然后计算这个数字的倒数。如果用户输入了0,我们就会抛出一个异常,因为0没有倒数。

            cpp

            #include <iostream>  
              
            int main() {  
                int number;  
                std::cout << "请输入一个数字:";  
                std::cin >> number;  
              
                try {  
                    // 检查是否输入了0  
                    if (number == 0) {  
                        // 抛出一个异常  
                        throw "哎呀!你不能输入0,因为0没有倒数!";  
                    }  
                    // 计算并输出数字的倒数  
                    std::cout << "数字的倒数是:" << 1.0 / number << std::endl;  
                } catch (const char* msg) {  
                    // 捕获到异常,输出异常信息  
                    std::cout << "发生异常了:" << msg << std::endl;  
                }  
              
                return 0;  
            }
            

            在这个例子中,如果用户输入了0,程序就会抛出一个异常("哎呀!你不能输入0,因为0没有倒数!"),然后跳转到catch块中执行,输出"发生异常了:哎呀!你不能输入0,因为0没有倒数!"。如果用户输入了一个非0的数字,程序就会正常计算并输出这个数字的倒数。

            总结 异常处理就是用来处理程序中可能发生的不正常情况的一种机制。在C++中,我们使用try和catch来处理异常。把可能会引发异常的代码放在try块中,然后在catch块中处理这些异常。这样,即使程序遇到了问题,也能够给出友好的提示,而不是直接崩溃。

            • 1