Sumber dimuat naik... memuat...

Kaedah penulisan pengetahuan C++ Pemulihan memori C++

Penulis:Pencipta Kuantiti - Impian Kecil, Dicipta: 2017-12-29 11:00:02, Dikemas kini: 2017-12-29 11:25:11

Kaedah penulisan pengetahuan C++ Pemulihan memori C++

Sebelum menulis strategi C++, ada beberapa pengetahuan asas yang perlu anda ketahui, tidak memerlukan kemahiran seperti Confucius, sekurang-kurangnya ketahui peraturan ini. Berikut adalah bahan untuk dipindahkan:

  • Pertempuran objek memori C++

Jika seseorang yang menyebut dirinya seorang programmer yang baik tetapi tidak tahu apa-apa tentang memori, maka saya boleh memberitahu anda bahawa dia pasti membanggakan diri. Menulis program dalam C atau C++, perlu memberi lebih banyak perhatian kepada memori, bukan sahaja kerana pembahagian memori yang munasabah secara langsung mempengaruhi kecekapan dan prestasi program, tetapi lebih penting lagi, apabila kita mengendalikan memori, masalah akan timbul secara tidak sengaja, dan banyak kali, masalah ini tidak mudah dikesan, seperti kebocoran memori, seperti penunjuk gantung. Saya di sini hari ini bukan untuk membincangkan bagaimana untuk mengelakkan masalah ini, tetapi untuk mengenali objek memori C++ dari sudut lain.

Kita tahu bahawa C++ membahagikan memori kepada tiga kawasan logik: heap, heap dan statik. Oleh itu, saya akan menyebut objek yang terletak di dalamnya sebagai objek heap, heap dan statik. Jadi apa perbezaan antara objek memori yang berbeza?

  • 1 Konsep asas

    Mari kita lihat terlebih dahulu ──, yang biasanya digunakan untuk menyimpan pembolehubah atau objek tempatan, seperti objek yang kita ungkapkan dalam definisi fungsi seperti berikut:

    Type stack_object ; 
    

    Stack_object adalah objek yang mempunyai jangka hayat yang bermula pada titik definisi dan berakhir apabila fungsi yang digunakan dikembalikan.

    Di samping itu, hampir semua objek sementara adalah objek kerucut. Sebagai contoh, definisi fungsi berikut:

    Type fun(Type object);
    

    Fungsi ini menghasilkan sekurang-kurangnya dua objek sementara, pertama, parameter yang dihantar mengikut nilai, jadi akan memanggil fungsi pembina salinan untuk menghasilkan objek sementara object_copy1, yang digunakan dalam fungsi bukan object, tetapi object_copy1, secara semula jadi, object_copy1 adalah objek kurung, yang dibebaskan apabila fungsi kembali; dan fungsi ini adalah nilai yang dikembalikan, apabila fungsi kembali, maka juga akan menghasilkan objek sementara object_copy2, yang akan dibebaskan beberapa ketika selepas fungsi kembali; contohnya, fungsi mempunyai kod berikut:

    Type tt ,result ; //生成两个栈对象
    
    tt = fun(tt); //函数返回时,生成的是一个临时对象object_copy2
    

    Pelaksanaan ayat kedua di atas adalah seperti ini, mula-mula menghasilkan objek sementara object_copy2 apabila fungsi fun dikembalikan, dan kemudian memanggil pengendali penugasan untuk dijalankan.

    tt = object_copy2 ; //调用赋值运算符
    

    Adakah anda lihat? Pengkompiler menghasilkan banyak objek sementara untuk kita tanpa kita sedari, dan pengeluaran masa dan ruang untuk menghasilkan objek sementara ini mungkin besar, jadi, anda mungkin faham mengapa untuk objek yang lebih baik untuk dihantar dengan rujukan const dan bukannya parameter fungsi dengan nilai.

    Seterusnya, lihat heap. Heap, juga dikenali sebagai ruang simpanan bebas, ia dialokasikan secara dinamik semasa pelaksanaan program, jadi ciri utamanya adalah dinamika. Dalam C ++, semua objek heap dicipta dan dimusnahkan oleh pengaturcara, jadi, masalah memori akan berlaku jika dikendalikan dengan tidak baik. Jika objek heap dialokasikan, tetapi lupa untuk membebaskan, kebocoran memori akan berlaku; dan jika objek telah dibebaskan, tetapi tidak menetapkan penunjuk yang sesuai sebagai NULL, penunjuk ini adalah yang dikenali sebagai penunjuk gantung gantung, apabila digunakan semula, akses tidak sah akan berlaku, menyebabkan kerosakan program yang serius.

    Jadi, bagaimana untuk mengalokasikan objek timbunan dalam C++? Satu-satunya cara adalah menggunakan new (juga boleh mendapatkan memori timbunan C dengan arahan jenis malloc, tentu saja), hanya menggunakan new untuk mengalokasikan sekeping memori dalam timbunan dan mengembalikan penunjuk ke objek timbunan tersebut.

    Kembali ke ruang simpanan statik. Semua objek statik dan global dialokasikan ke dalam ruang simpanan statik. Mengenai objek global, ia dialokasikan sebelum fungsi main. Sebenarnya, sebelum menjalankan kod paparan dalam fungsi main, fungsi main yang dihasilkan oleh penyusun dipanggil, sementara fungsi main melakukan kerja pembinaan dan inisialisasi semua objek global.

    void main(void)
    {
        ... // 显式代码
    }
    
    // 实际上转化为这样:
    
    void main(void)
    {
        _main(); //隐式代码,由编译器产生,用以构造所有全局对象
        ...      // 显式代码
        ...
        exit() ; // 隐式代码,由编译器产生,用以释放所有全局对象
    }
    

    Oleh itu, dengan mengetahui ini, kita boleh membuat beberapa teknik seperti, andaikan kita perlu melakukan beberapa persiapan sebelum fungsi main() dijalankan, maka kita boleh menulis kerja-kerja persiapan ini ke dalam fungsi pembina objek global yang ditetapkan, sehingga sebelum kod eksplisit fungsi main() dijalankan, fungsi pembina objek global ini akan dipanggil dan melakukan tindakan yang diharapkan, sehingga mencapai tujuan kita. Jika objek global dalam ruang simpanan statik, maka objek statik tempatan?

    Satu lagi objek statik ialah ia merupakan ahli statik dalam kelas. Masalah yang lebih rumit timbul apabila mempertimbangkan keadaan ini.

    Masalah pertama ialah jangka hayat objek ahli statik kelas, objek ahli statik kelas yang dihasilkan dengan penciptaan objek kelas pertama dan mati pada akhir program; iaitu, terdapat keadaan di mana dalam program kita mentakrifkan sebuah kelas yang mempunyai satu objek statik sebagai ahli, tetapi dalam proses pelaksanaan program, jika kita tidak mencipta mana-mana objek kelas, maka tidak akan menghasilkan objek statik yang terkandung dalam kelas; dan, jika banyak objek kelas dibuat, maka semua objek ini berkongsi anggota objek statik.

    Masalah kedua ialah apabila berlaku situasi berikut:

    class Base
    {
    public:
        static Type s_object ;
    }
    
    class Derived1 : public Base / / 公共继承
    {
    
        ... // other data 
    
    }
    
    class Derived2 : public Base / / 公共继承
    {
    
        ... // other data 
    
    }
    
    Base example ;
    
    Derivde1 example1 ;
    
    Derivde2 example2 ;
    
    example.s_object = …… ;
    
    example1.s_object = …… ; 
    
    example2.s_object = …… ; 
    

    Perhatikan bahawa ketiga-tiga frasa di atas yang dilabelkan sebagai blackbody, apakah s_object yang mereka lawati adalah objek yang sama? Jawapannya adalah ya, mereka memang menunjuk kepada objek yang sama, yang tidak terdengar seperti benar, bukan? Tetapi ini adalah benar, anda boleh menulis satu petikan kod mudah untuk memverifikasi sendiri. Apa yang saya akan lakukan adalah untuk menjelaskan mengapa ini berlaku.

    Mari kita fikirkan bahawa apabila kita menghantar objek jenis Derived1 kepada fungsi yang menerima parameter jenis Base yang tidak merujuk, pemotongan akan berlaku. Bagaimana pemotongan itu?

    Semua objek kelas derivatif yang mewarisi kelas BASE mengandungi subobjek jenis BASE (ini adalah kunci yang boleh diarahkan ke objek Derived1 dengan petunjuk jenis BASE, yang secara semula jadi juga merupakan kunci multi-modal), sementara semua subobjek dan semua objek jenis BASE berkongsi objek s_object yang sama, secara semula jadi, semua contoh kelas dalam keseluruhan sistem mewarisi yang berasal dari kelas BASE akan berkongsi objek s_object yang sama.

  • 2 Perbandingan tiga jenis objek memori

    Kelebihan objek kerucut ialah ia dihasilkan secara automatik pada masa yang sesuai dan dimusnahkan pada masa yang sesuai, tanpa perlu pengaturcara bimbang; dan objek kerucut biasanya dibuat dengan lebih cepat daripada objek tumpukan, kerana operasi operator new akan dipanggil ketika mengalokasikan objek tumpukan, operator new akan menggunakan beberapa algoritma carian ruang memori, yang mungkin memakan masa yang lama, dan menghasilkan objek kerucut tidak begitu rumit, ia hanya memerlukan penunjuk kerucut yang bergerak. Tetapi perlu diperhatikan bahawa biasanya kapasiti ruang kerucut adalah lebih kecil, biasanya 1 MB ke 2 MB, jadi objek yang lebih besar tidak sesuai dalam pengagihan kerucut. Perhatian khusus harus diberikan kepada fungsi regresi yang lebih baik untuk menggunakan objek kerucut, kerana dengan peningkatan kedalaman panggilan regresi, ruang kerucut yang diperlukan juga akan meningkat secara beransur-ansur, dan apabila ruang yang tidak mencukupi diperlukan, ia akan menyebabkan kebocoran kerucut, yang akan menyebabkan kesalahan.

    Objek timbunan yang dicipta dan dimusnahkan adalah sesuatu yang perlu ditentukan oleh pengaturcara, iaitu pengaturcara mempunyai kawalan penuh terhadap kehidupan objek timbunan. Kami sering memerlukan objek seperti ini, sebagai contoh, kami perlu membuat objek yang boleh diakses oleh beberapa fungsi, tetapi tidak mahu menjadikannya global, maka pada masa ini membuat objek timbunan pasti merupakan pilihan yang baik, dan kemudian menyampaikan petunjuk objek timbunan ini di antara fungsi-fungsi yang berbeza, untuk mencapai perkongsian objek tersebut. Di samping itu, kapasiti timbunan jauh lebih besar berbanding ruang simpanan.

    Kita lihat objek statik seterusnya.

    Pertama adalah objek global. Objek global menyediakan cara yang paling mudah untuk komunikasi antara kelas dan komunikasi antara fungsi, walaupun cara ini tidak elegan. Secara umum, dalam bahasa berorientasikan objek sepenuhnya, tidak ada objek global, seperti C #, kerana objek global bermaksud tidak selamat dan tinggi perpaduan, menggunakan objek global yang berlebihan dalam program akan mengurangkan ketahanan, kestabilan, penyelenggaraan dan kebolehgunaan program.

    Seterusnya adalah ahli statik kelas, yang telah disebutkan di atas, semua objek kelas induk dan kelas derivatifnya berkongsi objek ahli statik ini, jadi anggota statik seperti ini pasti merupakan pilihan yang baik apabila perlu berkongsi atau berkomunikasi data antara kelas atau objek kelas ini.

    Kemudian objek tempatan statik, yang digunakan untuk menyimpan keadaan tengah semasa fungsi di mana objek itu berada dipanggil berulang kali, salah satu contoh yang paling menonjol adalah fungsi berulang, kita semua tahu bahawa fungsi berulang adalah fungsi yang memanggil sendiri, jika objek tempatan bukan statik ditakrifkan dalam fungsi berulang, maka apabila jumlah berulangnya cukup besar, pengeluaran yang dihasilkan juga besar. Ini kerana objek tempatan bukan statik adalah objek yang tidak stabil, setiap panggilan berulang menghasilkan objek seperti ini, setiap kembalinya melepaskan objek ini, dan objek seperti ini hanya terhad kepada lapisan panggilan semasa, tidak dapat dilihat untuk lapisan yang lebih dalam dan lapisan yang lebih cerah.

    Dalam reka bentuk fungsi berulang, objek statik boleh digunakan sebagai pengganti objek tempatan bukan statik (iaitu objek kerucut), yang bukan sahaja mengurangkan perbelanjaan untuk menghasilkan dan melepaskan objek bukan statik setiap kali panggilan berulang dan kembali, tetapi objek statik juga dapat menyimpan keadaan tengah untuk panggilan berulang dan boleh diakses oleh setiap lapisan panggilan.

  • 3 Kecelakaan dengan menggunakan bahan yang tidak disyorkan

    Seperti yang telah diperkenalkan di atas, objek kerucut dicipta pada masa yang sesuai dan kemudian dibebaskan secara automatik pada masa yang sesuai, iaitu objek kerucut mempunyai fungsi pengurusan automatik. Jadi objek kerucut akan dibebaskan secara automatik di mana? Pertama, pada akhir hayatnya; kedua, apabila fungsi di mana ia berada berlaku kelainan.

    Objek kerucut, apabila dilepaskan secara automatik, akan memanggil fungsi pembongkaran sendiri. Jika kita membungkus sumber dalam objek kerucut, dan melakukan tindakan untuk melepaskan sumber dalam fungsi pembongkaran objek kerucut, maka kemungkinan kebocoran sumber akan berkurang dengan ketara, kerana objek kerucut boleh melepaskan sumber secara automatik, walaupun apabila fungsi yang berlaku berlaku. Proses yang sebenarnya adalah seperti ini: apabila fungsi dikeluarkan secara tidak normal, terdapat apa yang disebut stack_unwinding (kembalian kerucut) yang akan berlaku, iaitu, kerucut akan dibuka di dalam timbunan, kerana objek kerucut, secara semula jadi terdapat di dalam kerucut, jadi fungsi pembongkaran objek kerucut akan dijalankan semasa pembongkaran kembali, sehingga melepaskan sumber yang dikurung kecil.

  • 4 Larangan untuk mencipta objek timbunan

    Seperti yang dinyatakan di atas, jika anda memutuskan untuk melarang penciptaan objek heap jenis tertentu, maka anda boleh membuat kelas pembungkus sumber sendiri, yang hanya boleh dihasilkan di keranjang, untuk melepaskan sumber pembungkus secara automatik dalam keadaan yang luar biasa.

    Jadi bagaimana untuk melarang pembentukan objek timbunan? Kita sudah tahu, satu-satunya cara untuk menghasilkan objek timbunan adalah menggunakan new, jika kita melarang penggunaan new tidak akan berfungsi. Selanjutnya, new akan memanggil operator new semasa pelaksanaan, dan operator new boleh dimuat semula. Ada cara untuk membuat new operator private, untuk simetri, lebih baik untuk memuat semula operator private juga. Sekarang, anda mungkin bertanya lagi, adakah untuk membuat objek timbunan tidak perlu memanggil new?

    #include <stdlib.h> //需要用到C式内存分配函数
    
    class Resource ; //代表需要被封装的资源类
    
    class NoHashObject
    {
    private: 
        Resource* ptr ;//指向被封装的资源
    
        ... ... //其它数据成员
    
        void* operator new(size_t size) //非严格实现,仅作示意之用
        { 
            return malloc(size) ; 
        } 
    
        void operator delete(void* pp) //非严格实现,仅作示意之用
        { 
            free(pp) ; 
        } 
    
    public: 
        NoHashObject() 
        { 
            //此处可以获得需要封装的资源,并让ptr指针指向该资源
    
            ptr = new Resource() ; 
        } 
        
        ~NoHashObject() 
        { 
    
            delete ptr ; //释放封装的资源
        } 
    }; 
    

    NoHashObject kini merupakan kelas yang melarang objek yang terkumpul jika anda menulis kod berikut:

    NoHashObject* fp = new NoHashObject (()) ; // Kesalahan pengumpulan!

    menghapuskan fp;

    Kod di atas akan menghasilkan kesilapan masa penyusun. Baiklah, sekarang anda tahu bagaimana untuk merancang kelas yang melarang objek heap, anda mungkin mempunyai soalan seperti saya, adakah tidak mungkin untuk menghasilkan objek heap jenis ini jika definisi kelas NoHashObject tidak dapat diubah? Tidak, adakah ada cara, saya memanggilnya pemangkasan kekerasan yang kuat. C ++ sangat kuat, kuat sehingga anda boleh melakukannya dengan apa sahaja yang anda mahu.

    void main(void)
    {
        char* temp = new char[sizeof(NoHashObject)] ; 
    
        //强制类型转换,现在ptr是一个指向NoHashObject对象的指针
    
        NoHashObject* obj_ptr = (NoHashObject*)temp ; 
    
        temp = NULL ; //防止通过temp指针修改NoHashObject对象
    
        //再一次强制类型转换,让rp指针指向堆中NoHashObject对象的ptr成员
    
        Resource* rp = (Resource*)obj_ptr ; 
    
        //初始化obj_ptr指向的NoHashObject对象的ptr成员
    
        rp = new Resource() ; 
    
        //现在可以通过使用obj_ptr指针使用堆中的NoHashObject对象成员了
    
        ... ... 
    
        delete rp ;//释放资源
    
        temp = (char*)obj_ptr ; 
    
        obj_ptr = NULL ;//防止悬挂指针产生
    
        delete [] temp ;//释放NoHashObject对象所占的堆空间。
    
        } 
    

    Implementasi di atas adalah rumit, dan implementasi ini hampir tidak digunakan dalam amalan, tetapi saya masih menulis jalan, kerana memahaminya adalah berguna untuk memahami objek memori C ++.

    Data dalam memori adalah tidak berubah, dan jenisnya adalah kacamata yang kita pakai, dan apabila kita memakai kacamata, kita akan menggunakan jenis yang sesuai untuk menafsirkan data dalam memori, sehingga tafsiran yang berbeza memberikan maklumat yang berbeza.

    Pengubahsuaian jenis yang dipaksa sebenarnya adalah menukar kacamata lain dan melihat data memori yang sama lagi.

    Perlu juga diingatkan bahawa susunan data ahli objek mungkin berbeza di antara penyusun yang berbeza, contohnya, kebanyakan penyusun menyusun ahli penunjuk ptr NoHashObject pada 4 bait pertama ruang objek untuk memastikan tindakan penukaran dalam pernyataan berikut dijalankan seperti yang kita jangkakan:

    Sumber* rp = (Sumber*)obj_ptr;

    Walau bagaimanapun, tidak semua penyunting adalah demikian.

    Oleh kerana kita boleh melarang sesuatu jenis objek heap, adakah kita boleh merancang kelas yang tidak boleh menghasilkan objek kerucut?

  • 5 Larangan untuk menghasilkan objek kerucut

    Seperti yang telah disebutkan di atas, apabila membuat objek kerucut, penunjuk kerucut akan dipindahkan untuk memindahkan kerucut ke ruang yang sesuai untuk kerucut, dan kemudian memanggil fungsi pembina yang sesuai untuk membentuk objek kerucut secara langsung di ruang ini, dan apabila fungsi itu kembali, ia akan memanggil fungsi pembinaannya untuk membebaskan objek itu, dan kemudian menyesuaikan penunjuk kerucut untuk mengambil semula memori kerucut tersebut. Operator baru / hapus tidak diperlukan dalam proses ini, jadi menetapkan operator baru / hapus sebagai peribadi tidak dapat mencapai tujuan.

    Ini boleh, dan saya juga berhasrat untuk menggunakan kaedah ini. Tetapi sebelum ini, satu perkara yang perlu dipertimbangkan adalah bahawa jika kita menetapkan fungsi pembina sebagai peribadi, maka kita tidak boleh menggunakan new untuk menghasilkan objek timbunan secara langsung, kerana new akan memanggil fungsi pembina setelah memberi ruang kepada objek. Jadi, saya hanya akan menetapkan fungsi pembina sebagai peribadi.

    Jika kelas tidak dimaksudkan sebagai kelas asas, penyelesaian yang biasa digunakan adalah untuk mengisytiharkan fungsi penyusunnya sebagai peribadi.

    Untuk mengehadkan objek yang terhad, tetapi tidak mengehadkan pewarisan, kita boleh mengisytiharkan fungsi pembentukan analisis sebagai dilindungi, sehingga kedua-duanya baik. Seperti yang ditunjukkan dalam kod berikut:

    class NoStackObject
    {
    protected: 
    
        ~NoStackObject() { } 
    
    public: 
    
        void destroy() 
    
        { 
    
            delete this ;//调用保护析构函数
    
        } 
    }; 
    

    Kemudian, anda boleh menggunakan kelas NoStackObject seperti ini:

    NoStackObject* hash_ptr = baru NoStackObject() ;

    ...... // melakukan operasi pada objek yang diarahkan ke hash_ptr

    hash_ptr->destroy (()); Pergilah. Oh, adakah anda rasa agak pelik, kita membuat objek dengan new, tetapi tidak menggunakan delete untuk menghapusnya, tetapi menggunakan kaedah memusnahkan. Jelas, pengguna tidak biasa dengan cara yang aneh ini. Oleh itu, saya memutuskan untuk menetapkan fungsi pembina juga sebagai peribadi atau dilindungi. Ini kembali kepada soalan yang telah dihindari di atas, iaitu tanpa menggunakan new, maka bagaimana untuk menghasilkan objek?

    class NoStackObject
    {
    protected: 
    
        NoStackObject() { } 
    
        ~NoStackObject() { } 
    
    public: 
    
        static NoStackObject* creatInstance() 
        { 
            return new NoStackObject() ;//调用保护的构造函数
        } 
    
        void destroy() 
        { 
    
            delete this ;//调用保护的析构函数
    
        } 
    };
    

    Sekarang anda boleh menggunakan kelas NoStackObject seperti ini:

    NoStackObject* hash_ptr = NoStackObject::creatInstance() ;

    ...... // melakukan operasi pada objek yang diarahkan ke hash_ptr

    hash_ptr->membinasakan() ;

    hash_ptr = NULL; // Menghalang penggunaan penunjuk gantung

    Sekarang, adakah ia terasa lebih baik, operasi untuk menghasilkan objek dan melepaskan objek adalah sama?

  • Kaedah kitar semula sampah dalam C++

    Banyak pengaturcara C atau C++ mengkritik pembaharuan sampah dengan menganggap bahawa pembaharuan sampah pasti lebih tidak cekap daripada mereka menguruskan memori dinamik, dan pada masa pembaharuan program pasti akan berhenti di sana, dan jika mereka mengawal pengurusan memori, masa peruntukan dan pelepasan adalah stabil dan tidak menyebabkan program berhenti. Akhirnya, banyak pengaturcara C/C++ yakin bahawa mekanisme pembaharuan sampah tidak dapat dilaksanakan dalam C/C++.

    Pada hakikatnya, mekanisme kitar semula sampah tidak perlahan dan bahkan lebih cekap daripada pembahagian memori dinamik. Oleh kerana kita hanya boleh memperuntukkan tanpa melepaskan, maka pembahagian memori hanya memerlukan memori baru dari timbunan, petunjuk timbunan bergerak sudah cukup; dan proses pelepasan dihilangkan, dan secara semula jadi dipercepatkan. Algoritma kitar balik sampah moden telah berkembang banyak, dan algoritma pengumpulan kuantiti telah membolehkan proses pengumpulan sampah dilakukan secara bertahap, mengelakkan proses yang terganggu; sedangkan algoritma pengurusan memori dinamik tradisional juga mempunyai kelebihan untuk mengumpulkan serpihan memori pada masa yang tepat, tidak lebih daripada kitar semula sampah.

    Algoritma pemulihan sampah biasanya berasaskan pada mengimbas dan menandai semua blok memori yang mungkin digunakan pada masa ini, dan memulihkan memori yang tidak ditandakan dari semua memori yang telah diperuntukkan. Pada C/C++, pandangan bahawa pemulihkan sampah tidak dapat dicapai biasanya berasaskan pada ketidakupayaan untuk mengimbas dengan betul semua blok memori yang mungkin masih digunakan, namun, apa yang kelihatan mustahil sebenarnya tidak rumit. Pertama, dengan mengimbas data memori, penunjuk yang dialokasikan secara dinamik ke dalam simpanan mudah diiktiraf, dan jika terdapat kesalahan pengenalan, hanya dapat menunjuk beberapa data bukan penunjuk sebagai penunjuk, dan tidak menunjuk sebagai data bukan penunjuk.

    Apabila membaiki sampah, hanya perlu mengimbas segmen bss, segmen data dan ruang simpanan yang sedang digunakan untuk mencari jumlah yang mungkin merupakan penunjuk memori dinamik, memindai semula memori yang dirujuk dapat mendapatkan semua memori dinamik yang sedang digunakan.

    Sekiranya anda ingin mewujudkan pengendali sampah yang baik untuk projek anda, ia mungkin untuk meningkatkan kelajuan pengurusan memori atau bahkan mengurangkan penggunaan memori keseluruhan. Jika berminat, carilah kertas kerja dan perpustakaan yang telah dilaksanakan di internet, yang penting bagi seorang pengaturcara.

    DibaharuiHK Zhang

  • Apabila alamat pembolehubah tempatan diberikan kepada penunjuk, mengapa kitaran kehidupannya boleh dilanjutkan sehingga akhir keseluruhan program?

    #include<stdio.h>
    int*fun(){
        int k = 12;
        return &k;
    }
    int main(){
        int *p = fun();    
        printf("%d\n", *p);
    
        getchar();
        return 0;
    }
    

    Tidak hanya boleh diakses, tetapi juga boleh diubah, tetapi akses itu tidak pasti. Alamat pembolehubah tempatan berada di dalam timbunan program sendiri, dan selepas pembolehubah pihak berkuasa berakhir, nilainya masih wujud selagi tidak memberikan alamat memori pembolehubah tempatan kepada pembolehubah lain. Tetapi jika diubah, ia adalah agak berbahaya kerana alamat memori ini mungkin diberikan kepada pembolehubah lain dalam program, yang mungkin menyebabkan kerosakan program jika diubah secara paksa melalui penunjuk.

    csdn bbs


Lebih lanjut