MST

星途 面试题库

面试题:C++类普通成员函数参数传递中的生命周期管理与内存安全

考虑一个C++类 `MyClass`,它有一个普通成员函数 `void handle(std::unique_ptr<int[]> ptr)`。如果在函数调用时传入一个 `std::unique_ptr<int[]>` 临时对象,在函数内部可能会对 `ptr` 进行释放、重新分配等操作。请分析在这种情况下,如何确保内存安全并且避免悬空指针等问题?如果函数需要返回 `ptr`,又该如何设计以保证正确的资源管理?请给出详细的代码实现和解释。
34.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 确保内存安全和避免悬空指针
    • handle函数内部,std::unique_ptr<int[]>会在函数结束时自动释放其所管理的内存,所以一般情况下不会产生悬空指针。但是如果对ptr进行释放操作,需要确保不再使用它。
    • 以下是代码示例:
#include <memory>
#include <iostream>

class MyClass {
public:
    void handle(std::unique_ptr<int[]> ptr) {
        // 这里可以对ptr进行操作,比如释放内存
        ptr.reset(); // 释放内存,ptr变为nullptr,避免悬空指针
    }
};
  • 解释:std::unique_ptr的设计理念就是自动管理动态分配的内存。当ptr离开其作用域(即handle函数结束)时,std::unique_ptr的析构函数会自动释放其所指向的内存。如果在函数内部调用reset,会立即释放当前管理的内存,并将ptr置为nullptr,这样就避免了悬空指针问题。
  1. 函数需要返回ptr时的资源管理设计
    • 当函数需要返回ptr时,std::unique_ptr能够完美地进行资源转移。std::unique_ptr支持移动语义,这使得在返回时资源的所有权能够安全地转移。
    • 以下是代码示例:
#include <memory>
#include <iostream>

class MyClass {
public:
    std::unique_ptr<int[]> handle(std::unique_ptr<int[]> ptr) {
        // 这里可以对ptr进行操作,比如重新分配内存
        ptr.reset(new int[5]);
        for (int i = 0; i < 5; i++) {
            ptr[i] = i;
        }
        return ptr; // 移动语义,将ptr的所有权返回
    }
};
  • 解释:在handle函数中,ptr重新分配了内存并进行了初始化。当return ptr时,std::unique_ptr使用移动语义将资源的所有权从函数内部的ptr转移到函数调用者。这意味着不会进行内存的拷贝,而是直接将内部指针和相关资源转移,从而保证了资源的正确管理。调用者接收到返回的std::unique_ptr后,就拥有了对这块内存的唯一所有权,并且在其析构时会正确释放内存。

可以这样测试上述代码:

int main() {
    MyClass obj;
    std::unique_ptr<int[]> temp(new int[3]);
    std::unique_ptr<int[]> result = obj.handle(std::move(temp));
    if (result) {
        for (int i = 0; i < 5; i++) {
            std::cout << result[i] << " ";
        }
        std::cout << std::endl;
    }
    return 0;
}

main函数中,我们创建了一个临时的std::unique_ptr<int[]>,并通过std::move将其所有权转移到handle函数中,handle函数返回的std::unique_ptr<int[]>result接收,然后我们可以使用result来访问分配的内存。