MST

星途 面试题库

面试题:C++ 智能指针的内存管理与循环引用问题

假设有两个类A和B,A类中有一个std::shared_ptr<B>类型的成员变量,B类中有一个std::shared_ptr<A>类型的成员变量,这可能会导致循环引用问题。请编写代码展示这种循环引用情况,并说明如何使用std::weak_ptr来解决该问题。
14.9万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

展示循环引用情况的代码

#include <iostream>
#include <memory>

class B;

class A {
public:
    std::shared_ptr<B> b;
    ~A() {
        std::cout << "A destroyed" << std::endl;
    }
};

class B {
public:
    std::shared_ptr<A> a;
    ~B() {
        std::cout << "B destroyed" << std::endl;
    }
};

void testCycle() {
    std::shared_ptr<A> ptrA = std::make_shared<A>();
    std::shared_ptr<B> ptrB = std::make_shared<B>();
    ptrA->b = ptrB;
    ptrB->a = ptrA;
}

在上述代码中,testCycle函数创建了ABshared_ptr实例,并互相持有对方的shared_ptr,这就形成了循环引用。当函数结束时,ptrAptrB的引用计数不会归零,AB的析构函数不会被调用,造成内存泄漏。

使用std::weak_ptr解决循环引用问题的代码

#include <iostream>
#include <memory>

class B;

class A {
public:
    std::weak_ptr<B> b;
    ~A() {
        std::cout << "A destroyed" << std::endl;
    }
};

class B {
public:
    std::weak_ptr<A> a;
    ~B() {
        std::cout << "B destroyed" << std::endl;
    }
};

void testNoCycle() {
    std::shared_ptr<A> ptrA = std::make_shared<A>();
    std::shared_ptr<B> ptrB = std::make_shared<B>();
    ptrA->b = ptrB;
    ptrB->a = ptrA;
}

在这个改进版本中,A类和B类中的成员变量改为std::weak_ptr类型。weak_ptr不会增加对象的引用计数,这样当testNoCycle函数结束时,ptrAptrB的引用计数会归零,AB的析构函数会被调用,避免了循环引用导致的内存泄漏。如果需要通过weak_ptr访问对象,可以使用lock方法,例如:

void accessObject() {
    std::shared_ptr<A> ptrA = std::make_shared<A>();
    std::shared_ptr<B> ptrB = std::make_shared<B>();
    ptrA->b = ptrB;
    ptrB->a = ptrA;

    std::shared_ptr<B> lockedB = ptrA->b.lock();
    if (lockedB) {
        // 可以安全地使用lockedB
    }
}