MST

星途 面试题库

面试题:C++ 中引用与指针在异常处理时的区别

请阐述在 C++ 中,引用和指针在异常处理机制下的不同表现,例如在函数调用栈展开过程中,它们对于对象生命周期管理以及内存释放方面有何差异,并举例说明。
41.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 引用在异常处理机制下的表现

  • 对象生命周期管理:引用一旦绑定到一个对象,就不能再绑定到其他对象。在函数调用栈展开过程中,如果一个函数内使用引用指向局部对象,当异常抛出导致函数提前结束时,局部对象的生命周期仍然遵循正常的规则,由其作用域决定。当作用域结束,对象自动销毁。
  • 内存释放:对于栈上的对象,引用不会改变内存释放的方式。如果引用指向的是堆上分配的对象,那么内存释放仍然依赖于对象的析构函数是否正确实现内存释放逻辑。例如,假设通过智能指针分配了对象并将引用绑定到它,当引用的作用域结束时,智能指针会管理内存释放;但如果是普通指针分配对象并用引用指向,需要手动释放内存,否则会导致内存泄漏。

2. 指针在异常处理机制下的表现

  • 对象生命周期管理:指针可以指向不同的对象,并且指针本身不影响所指对象的生命周期。在函数调用栈展开时,如果指针指向局部对象,当函数因异常提前结束,局部对象会正常销毁。但如果指针指向堆上分配的对象,对象的生命周期不会自动结束,需要手动释放内存。
  • 内存释放:在异常处理过程中,如果指针指向堆上分配的内存且没有在异常处理代码中正确释放,就会导致内存泄漏。例如,在函数内用new分配内存并使用指针指向它,若在释放内存之前抛出异常,且没有合适的try - catch块来释放内存,这块内存就无法再被访问和释放。

3. 举例说明

#include <iostream>

class Resource {
public:
    Resource() { std::cout << "Resource constructed" << std::endl; }
    ~Resource() { std::cout << "Resource destructed" << std::endl; }
};

void testReference() {
    Resource res;
    Resource& ref = res;
    try {
        throw std::runtime_error("Exception in testReference");
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }
    // 这里res对象会在作用域结束时正常销毁,ref不会影响其生命周期
}

void testPointer() {
    Resource* ptr = new Resource();
    try {
        throw std::runtime_error("Exception in testPointer");
    } catch (const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
        delete ptr; // 如果不手动释放,会导致内存泄漏
    }
}

int main() {
    std::cout << "Testing reference..." << std::endl;
    testReference();
    std::cout << "Testing pointer..." << std::endl;
    testPointer();
    return 0;
}

在上述代码中,testReference函数里引用ref指向栈上的Resource对象,当异常抛出并捕获后,res对象会正常销毁。而在testPointer函数里,指针ptr指向堆上的Resource对象,如果在捕获异常时不手动delete ptr,就会发生内存泄漏。