C++忘了学,学了忘,可是从未做过真正的项目,那为什么还会重复开头的场景呢?

由于一名Android工程师,C++是必备的技术,每一个产品,仔细去分析的时分都能发现很多模块都能够运用C++开发,从安全性、功能等方面都有协助。

之前关于C/C++的影响便是指针难学,概念多,还有各种内存问题,着实很烦。

智能指针,用于办理动态分配内存,以协助防止内存走漏和办理资源的生命周期。智能指针是与原始指针不同的,它们能够主动地盯梢目标的所有权,当目标不再需求时,主动开释内存。 就问你怕不怕。

智能指针分类

在C++ 规范库中,有四个只能指针 即

  1. std::auto_ptr
  2. std::unique_ptr
  3. std::shared_ptr
  4. std::weak_ptr

其间std::auto_ptr在C++ 98 规范中就存在,现在已经废弃,所以不做学习。

std::unique_ptr

std::unique_ptr是C++11引进的独占所有权智能指针。它答应一个目标拥有另一个目标的仅有所有权,当std::unique_ptr超出效果域时,它会主动开释目标的内存。

#include <memory>
std::unique_ptr<int> uniquePtr = std::make_unique<int>(42);

主要特点:

  1. 仅有所有权:每个std::unique_ptr实例拥有目标的仅有所有权。
  2. 高效且安全:没有额定的引证计数开支,适用于大多数状况。
  3. 可移动语义:能够运用std::move转移所有权。
  4. 不能同享:不能复制或同享所有权,因而不会导致资源走漏

std::shared_ptr

std::shared_ptr是C++11引进的同享所有权智能指针。它答应多个std::shared_ptr实例同享同一个目标的所有权,当最后一个std::shared_ptr超出效果域时,目标的内存将被开释。

#include <memory>
std::shared_ptr<int> sharedPtr1 = std::make_shared<int>(42);
std::shared_ptr<int> sharedPtr2 = sharedPtr1; // 同享所有权

主要特点:

  1. 同享所有权:多个std::shared_ptr能够同享同一个目标的所有权。
  2. 引证计数:内部保护引证计数,主动开释目标。
  3. 适用于循环引证:能够与std::weak_ptr一同用于处理循环引证问题。
  4. 有一定开支:引证计数可能引进一些额定的开支。

std::weak_ptr

std::weak_ptr也是C++11引进的,用于处理std::shared_ptr可能导致的循环引证问题。std::weak_ptr答应你调查std::shared_ptr办理的目标,但不拥有它。

#include <memory>
std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
std::weak_ptr<int> weakPtr = sharedPtr; // 弱引证

主要特点:

  1. 弱引证:不拥有目标,仅用于调查std::shared_ptr
  2. 防止循环引证:能够用于打破std::shared_ptr之间的循环引证,以防止内存走漏。

运用推荐

一般推荐运用std::unique_ptr来办理独占所有权的资源,运用std::shared_ptrstd::weak_ptr来办理同享所有权的资源和处理循环引证问题。防止运用已弃用的std::auto_ptr

shared_str — week_ptr

weak_ptr这个智能指针是用来辅佐shared_ptr作业的

在上面智能指针的介绍中,shared_ptr 是同享所有权智能指针,它的中心点在于同享,存在引证计数逻辑,在下面这种场景中,可能导致循环引证问题

#include <memory>
class A;
class B;
class A {
public:
    // 运用同享所有权智能指针
    std::shared_ptr<B> b_ptr;
    A() {
        std::cout << "A constructor" << std::endl;
    }
    ~A() {
        std::cout << "A destructor" << std::endl;
    }
};
class B {
public:
    std::shared_ptr<A> a_ptr;
    B() {
        std::cout << "B constructor" << std::endl;
    }
    ~B() {
        std::cout << "B destructor" << std::endl;
    }
};
int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();
    // 构成循环引证
    a->b_ptr = b;
    b->a_ptr = a;
    return 0;
}

在上面的示例中,类 AB 分别包括一个 std::shared_ptr,它们相互引证对方。当 ab 的引证计数都不再为零时,它们的析构函数永远不会被调用,导致内存走漏。

为了处理这个问题,能够运用 std::weak_ptr 来打破循环引证。std::weak_ptr 答应你调查 std::shared_ptr 办理的目标,但不拥有它,因而不会增加引证计数

以下是运用 std::weak_ptr 处理循环引证问题的代码

#include <memory>
#include <iostream>
class A;
class B;
class A {
public:
    // 运用 weak_ptr 代替 shared_ptr
    std::weak_ptr<B> b_weak_ptr;
    A() {
        std::cout << "A constructor" << std::endl;
    }
    ~A() {
        std::cout << "A destructor" << std::endl;
    }
};
class B {
public:
    // 运用 weak_ptr 代替 shared_ptr
    std::weak_ptr<A> a_weak_ptr;
    B() {
        std::cout << "B constructor" << std::endl;
    }
    ~B() {
        std::cout << "B destructor" << std::endl;
    }
};
int main() {
    // 创建 shared_ptr
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();
    // 运用 weak_ptr
    a->b_weak_ptr = b;
    b->a_weak_ptr = a;
    // 当 a 和 b 的引证计数为零时,它们的析构函数会被调用,不会出现内存走漏
    return 0;
}

std::weak_ptr 用于代替了 std::shared_ptr,并且在 main 函数的末尾显式地开释了 abshared_ptr,使它们的引证计数削减

关于 Java语言型选手,这个疑虑要消除

std::shared_ptr 和Java中的GC Roots(废物收集根节点)的确有一些相似之处,当看到引证计数这四个字时,肯定会想到GC roots 的算法

咱们来对比一下:

相似之处:

  1. 引证计数std::shared_ptr 和GC Roots 都与引证计数相关。std::shared_ptr 运用引证计数来盯梢有多少个智能指针实例引证了同一目标。GC Roots 也类似,它们是根节点,盯梢哪些目标被引证,哪些不再被引证。
  2. 生命周期办理std::shared_ptr 和GC Roots 都用于办理目标的生命周期。std::shared_ptr 经过引证计数来确保目标在没有引证时被开释,GC Roots 确保被引证的目标不会被废物收集器收回。
  3. 循环引证问题std::shared_ptr 和GC Roots 都能够处理循环引证问题。在std::shared_ptr 中,运用 std::weak_ptr 来打破循环引证,GC Roots 能够辨认不再可达的目标并开释它们。

不同之处

  1. 语言和环境std::shared_ptr 是C++中的一个智能指针,用于办理动态分配的内存。GC Roots 是Java虚拟机中的概念,用于废物收回。它们存在于不同的编程语言和执行环境中。
  2. 废物收集方式:GC Roots 一般与废物收回算法(如标记-清除、分代废物收回)一同运用,以辨认和收集不再可达的目标。而 std::shared_ptr 运用引证计数来盯梢目标的引证状况,不需求像废物收回器那样扫描整个目标图。
  3. 功能和开支:由于不同的废物收回算法和环境要求,GC Roots 可能会引进一些功能开支,而 std::shared_ptr 的开支一般较小。

总结

在C++编程中,智能指针是一种强壮的工具,可用于办理内存和资源,确保安全和高效的资源办理。std::shared_ptrstd::unique_ptr是现代C++中常用的智能指针类型,分别用于同享和独占资源所有权,在今后的开发中能够放心大胆的运用。