自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C++ RAII初探+析構(gòu)函數(shù)

開(kāi)發(fā) 前端
AII并不是一個(gè)新鮮的特性,而是古早就有的一種范式。上面例子展示了對(duì)象創(chuàng)建的時(shí)候獲取資源,對(duì)象銷毀的時(shí)候釋放資源的例子。

前言

早期編寫的C++是有缺陷的,舉些例子。比如裸指針滿天飛,多線程的數(shù)據(jù)競(jìng)爭(zhēng),雙重釋放等等。但如今的C++正在努力改善這些缺陷,RAII范式的編程在C++比重逐步增加。RAII(Resource Acquisition Is Initialization)是C++之父Bjarne Stroustrup在設(shè)計(jì)C++的時(shí)候就引入了。即:資源獲取即初始化。通俗點(diǎn),在對(duì)象創(chuàng)建的時(shí)候獲取資源,在對(duì)象銷毀的時(shí)候釋放資源。確保內(nèi)存的安全性。指針shared_ptr就是其中的杰作,下面也會(huì)講到。

本篇除了RAII之外,還會(huì)分析下其析構(gòu)函數(shù)的關(guān)聯(lián)。代碼部分,經(jīng)過(guò)C++20測(cè)試,均可跑通,可直接用。

RAII操作例子

一個(gè)非常簡(jiǎn)單的RAII操作,我們初始化對(duì)象的時(shí)候打開(kāi)了文件資源。然后在離開(kāi)對(duì)象的作用域的時(shí)候,會(huì)調(diào)用析構(gòu)函數(shù)釋放(關(guān)閉)文件資源,例子如下:

//filename:RAII.c
//compile:g++ -g -static -o RAII RAII.c


#include <iostream>
#include <memory>


class File {
public:
    File(const std::string& filename) {
        // 在構(gòu)造函數(shù)中打開(kāi)文件
        std::cout << "Opening file: " << filename << std::endl;
        file_ = fopen(filename.c_str(), "r");
        if (!file_) {
            throw std::runtime_error("Failed to open file");
        }
    }


    ~File() {
        // 在析構(gòu)函數(shù)中關(guān)閉文件
        if (file_) {
            std::cout << "Closing file." << std::endl;
            fclose(file_);
        }
    }


private:
    FILE* file_;
};


int main() {
    try {
        // 創(chuàng)建 File 對(duì)象,RAII 確保文件在生命周期結(jié)束時(shí)自動(dòng)關(guān)閉
        File f("example.txt");


        
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
    }


    
    return 0;
}

File對(duì)象的構(gòu)造函數(shù)里面打開(kāi)文件,上面代碼運(yùn)行的結(jié)果如下:

圖片圖片

在File對(duì)象f離開(kāi)作用域也即是try塊的結(jié)尾大括號(hào)處,會(huì)調(diào)用析構(gòu)函數(shù),關(guān)閉文件。

關(guān)于這點(diǎn)我們lldb驗(yàn)證下,且簡(jiǎn)略分析下其原理。在~File()析構(gòu)函數(shù)下斷,其堆棧是在RAII.c:36也即是try塊大括號(hào)結(jié)尾的地方調(diào)用了析構(gòu)函數(shù)。

如下:

(lldb) b ~File()
Breakpoint 2: where = RAII`File::~File() + 16 at RAII.c:17:13, address = 0x000000000040582c
(lldb) r&c
Process 4510 resuming
Opening file: example.txt
Process 4510 stopped
* thread #1, name = 'RAII', stop reason = breakpoint 2.1
    frame #0: 0x000000000040582c RAII`File::~File(this=0x00007fffffffe208) at RAII.c:17:13
   14
   15       ~File() {
   16           // 在析構(gòu)函數(shù)中關(guān)閉文件
-> 17           if (file_) {
   18               std::cout << "Closing file." << std::endl;
   19               fclose(file_);
   20           }
(lldb) bt
* thread #1, name = 'RAII', stop reason = breakpoint 2.1
  * frame #0: 0x000000000040582c RAII`File::~File(this=0x00007fffffffe208) at RAII.c:17:13
    frame #1: 0x00000000004055ef RAII`main at RAII.c:36:5
    frame #2: 0x00000000004b7ec8 RAII`__libc_start_call_main + 104
    frame #3: 0x00000000004ba090 RAII`__libc_start_main + 624
    frame #4: 0x0000000000405475 RAII`_start + 37

當(dāng)我們運(yùn)行到try塊收尾大括號(hào)處,看此時(shí)程序剛好調(diào)用了File::~File

(lldb) n
Opening file: example.txt
Process 4552 stopped
* thread #1, name = 'RAII', stop reason = step over
    frame #0: 0x00000000004055e3 RAII`main at RAII.c:33:5
   30           File f("example.txt");
   31
   32           // 文件操作...
-> 33       } catch (const std::exception& e) {
   34           std::cerr << e.what() << std::endl;
   35       }
   36
(lldb) di -s $pc
RAII`main:
->  0x4055e3 <+110>: lea    rax, [rbp - 0x58]
    0x4055e7 <+114>: mov    rdi, rax
    0x4055ea <+117>: call   0x40581c       ; File::~File at RAII.c:18:5
    0x4055ef <+122>: mov    eax, 0x0
    0x4055f4 <+127>: mov    rdx, qword ptr [rbp - 0x18]
    0x4055f8 <+131>: sub    rdx, qword ptr fs:[0x28]

也即是代碼:

0x4055ea <+117>: call   0x40581c       ; File::~File at RAII.c:18:5

RAII風(fēng)格指針

現(xiàn)代C++的幾個(gè)指針

  • std::unique_ptr:獨(dú)占所有權(quán)的智能指針。一個(gè) unique_ptr 只能有一個(gè)指針指向資源,因此它不支持復(fù)制,只支持轉(zhuǎn)移所有權(quán)。
  • std::shared_ptr:共享所有權(quán)的智能指針。多個(gè) shared_ptr 可以共享對(duì)資源的所有權(quán),只有最后一個(gè)指針被銷毀時(shí),資源才會(huì)被釋放。
  • std::weak_ptr:一種不影響資源生命周期的智能指針,用來(lái)打破循環(huán)引用的問(wèn)題

我們也來(lái)觀察下RAII指針自動(dòng)調(diào)用析構(gòu)函數(shù)釋放的例子

//filename:zhizhen.c
//compile:g++ -std=c++20 -g -static -o zhizhen zhizhen.c
#include <iostream>
#include <memory>


class Resource {
public:
    Resource(const std::string& name) : name_(name) {
        std::cout << name_ << " acquired!" << std::endl;
    }


    ~Resource() {
        std::cout << name_ << " released!" << std::endl;
    }


    void use() {
        std::cout << "Using " << name_ << std::endl;
    }


private:
    std::string name_;
};


void demonstrateWeakPtr() {
    // 創(chuàng)建 shared_ptr 管理 Resource 對(duì)象
    std::shared_ptr<Resource> sharedResource = std::make_shared<Resource>("Resource1");


    // 創(chuàng)建 weak_ptr 觀察 shared_ptr
    std::weak_ptr<Resource> weakResource = sharedResource;


    // weak_ptr 不增加引用計(jì)數(shù),它只是觀察資源
    std::cout << "Weak pointer created, but it does not affect resource's reference count." << std::endl;


    // 使用 weak_ptr 的 lock 方法來(lái)獲取 shared_ptr
    if (auto lockedResource = weakResource.lock()) {
        lockedResource->use();  // 使用資源
    } else {
        std::cout << "Failed to lock weak pointer, resource is not available." << std::endl;
    }


    // 當(dāng) shared_ptr 離開(kāi)作用域時(shí),資源會(huì)被釋放
}


int main() {
    demonstrateWeakPtr();  // 資源由 shared_ptr 管理,weak_ptr 只是觀察


    return 0;
}

它的結(jié)果如下,同樣的析構(gòu)函數(shù)在離開(kāi)作用域釋放

圖片圖片

結(jié)尾

RAII并不是一個(gè)新鮮的特性,而是古早就有的一種范式。上面例子展示了對(duì)象創(chuàng)建的時(shí)候獲取資源,對(duì)象銷毀的時(shí)候釋放資源的例子。

我們只需要寫好代碼的規(guī)范,其它的編譯器都給做了,比如析構(gòu)函數(shù)的調(diào)用等。這種操作,有效的防范了部分內(nèi)存泄露的可能性。

責(zé)任編輯:武曉燕 來(lái)源: 江湖評(píng)談
相關(guān)推薦

2010-01-18 15:53:27

C++析構(gòu)函數(shù)

2010-02-04 16:39:26

C++析構(gòu)函數(shù)

2011-07-15 01:29:39

C++析構(gòu)函數(shù)

2024-12-19 14:42:15

C++內(nèi)存泄漏內(nèi)存管理

2010-02-05 13:35:19

C++虛析構(gòu)函數(shù)

2009-08-14 17:24:28

C#構(gòu)造函數(shù)和析構(gòu)函數(shù)

2009-09-03 13:14:55

C#構(gòu)造函數(shù)C#析構(gòu)函數(shù)

2009-08-19 09:57:01

C++ RAII

2011-06-09 15:04:22

RAII機(jī)制

2009-07-30 15:24:13

C#析構(gòu)函數(shù)C#構(gòu)造函數(shù)

2021-12-11 19:02:03

函數(shù)C++對(duì)象

2011-06-15 09:47:14

C++

2010-01-20 14:25:56

函數(shù)調(diào)用

2025-04-11 07:50:00

虛析構(gòu)函數(shù)C++開(kāi)發(fā)

2024-12-11 16:00:00

C++函數(shù)編譯器

2010-01-25 10:10:42

C++函數(shù)參數(shù)

2009-09-02 10:49:46

C#調(diào)用析構(gòu)方法

2010-07-20 09:52:27

Perl構(gòu)造函數(shù)

2009-12-04 17:16:41

PHP析構(gòu)函數(shù)

2010-07-16 17:12:58

Perl析構(gòu)函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)