动态内存管理

本文最后更新于:2022年3月19日 凌晨

此文取自于👉动态内存管理 - cppreference.com

std::unique_ptr#

拥有独有对象所有权语义的智能指针

#include <iostream>
#include <vector>
#include <memory>
#include <cstdio>
#include <fstream>
#include <cassert>
#include <functional>

struct B {
    virtual void bar() { std::cout << "B::bar\n"; }
    virtual ~B() = default;
};
struct D : B
{
    D() { std::cout << "D::D\n";  }
    ~D() { std::cout << "D::~D\n";  }
    void bar() override { std::cout << "D::bar\n";  }
};

// 消费 unique_ptr 的函数能以值或以右值引用接收它
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}

void close_file(std::FILE* fp) { std::fclose(fp); }

int main()
{
    std::cout << "unique ownership semantics demo\n";
    {
        auto p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
        auto q = pass_through(std::move(p)); 
        assert(!p); // 现在 p 不占有任何内容并保有空指针
        q->bar();   // 而 q 占有 D 对象
    } // ~D 调用于此

    std::cout << "Runtime polymorphism demo\n";
    {
        std::unique_ptr<B> p = std::make_unique<D>(); // p 是占有 D 的 unique_ptr
        // 作为指向基类的指针
        p->bar(); // 虚派发

        std::vector<std::unique_ptr<B>> v;  // unique_ptr 能存储于容器
        v.push_back(std::make_unique<D>());
        v.push_back(std::move(p));
        v.emplace_back(new D);
        for(auto& p: v) p->bar(); // 虚派发
    } // ~D called 3 times

    std::cout << "Custom deleter demo\n";
    std::ofstream("demo.txt") << 'x'; // 准备要读的文件
    {
        std::unique_ptr<std::FILE, void (*)(std::FILE*) > fp(std::fopen("demo.txt", "r"),
                                                             close_file);
        if(fp) // fopen 可以打开失败;该情况下 fp 保有空指针
            std::cout << (char)std::fgetc(fp.get()) << '\n';
    } // fclose() 调用于此,但仅若 FILE* 不是空指针
    // (即 fopen 成功)

    std::cout << "Custom lambda-expression deleter demo\n";
    {
        std::unique_ptr<D, std::function<void(D*)>> p(new D, [](D* ptr)
                                                      {
                                                          std::cout << "destroying from a custom deleter...\n";
                                                          delete ptr;
                                                      });  // p 占有 D
        p->bar();
    } // 调用上述 lambda 并销毁 D

    std::cout << "Array form of unique_ptr demo\n";
    {
        std::unique_ptr<D[]> p{new D[3]};
    } // 调用 ~D 3 次
}

std::shared_ptr#

拥有共享对象所有权语义的智能指针

#include <iostream>
#include <memory>

class Sample
{
    public:
    Sample() { std::cout << "This is Sample." << std::endl; }


    void smartpointer()
    {
        std::cout << "This is smartpointer." << std::endl;
    }

    ~Sample() { std::cout << "Destory Sample." << std::endl; }
};

int main()
{
    auto pointer = std::make_shared<Sample>();
    // pointer->smartpointer();

    // std::shared_ptr<Sample> sample1(new Sample());
    std::shared_ptr<Sample> sample1 = pointer;
    sample1->smartpointer();

    std::shared_ptr<Sample> sample12(std::make_shared<Sample>());
    sample12->smartpointer();
    return 0;
}

std::weak_ptr#

std::shared_ptr 所管理对象的弱引用

std::weak_ptr 类型指针不会导致堆内存空间的引用计数增加或减少

std::shared_ptr依然存在着资源无法释放的问题,比如class A中有class B成员变量,class B中有class A成员变量,这种情况就存在引用计数不为0的问题。

#include <iostream>
#include <memory>

struct A;
struct B;

struct A
{
    //std::shared_ptr<B> pointer;
    std::weak_ptr<B> ptr;
    std::shared_ptr<B> ptr_ = ptr.lock();
    ~A()
    {
        std::cout << "A 被销毁" << std::endl;
    }
};
struct B
{
    //std::shared_ptr<A> pointer;
    std::weak_ptr<A> ptr;
    std::shared_ptr<A> ptr_ = ptr.lock();
    ~B()
    {
        std::cout << "B 被销毁" << std::endl;
    }
};
int main()
{
    auto a = std::make_shared<A>();
    //std::weak_ptr<A> ptr_a(a);
    auto b = std::make_shared<B>();
    //std::weak_ptr<B> ptr_b(b);
    a->ptr = b;
    //a->pointer = b;
    b->ptr = a;
    //b->pointer = a;
}

结果:

End.


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!