簡體   English   中英

沒有句柄的動態分配變量會發生什么? (C++)

[英]What Happens To Dynamically Allocated Variables Without Handles ? (C++)

像這樣實例化沒有句柄的類會導致 C++ 中的 memory 泄漏嗎?

new SomeClass();

在方法中傳遞它們怎么樣?

SomeMethod(new SomeClass())

在方法的定義超出 scope 之后,它們會被釋放嗎?

這聽起來像是一個愚蠢的問題,但據我所知,如果他們不被釋放,他們哪兒也去不了。

是的,你是對的。 默認 C++,每次調用new后都必須跟delete ,否則就是 leak。 但是,在某些邊緣情況下,可以在不使用delete的情況下使用new

一種這樣的情況是placement new ,其中 memory 分配由您自己處理。 例子:

#include <cstdint>
#include <memory>
#include <iostream>

struct X {
    int a;
    int b;
};

int main(int argc, char** argv) {

    char buffer[256];

    X* x1 = new (&buffer[0]) X{1,2};
    X* x2 = new (&buffer[8]) X{3,4};

    std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
    std::cout << "x2: " << x2->a << " " << x2->b << std::endl;

    // no leaks since the memory is released when `buffer` is 
    // deallocated. However it is good practice to call the 
    // destructor directly
    x1->~X();
    x2->~X();
}

產生:

Program stdout
x1: 1 2
x2: 3 4

Godbolt: https://godbolt.org/z/sEPWadcKh

另一種情況是當 class覆蓋 operator new時,如本例所示:

#include <cstdint>
#include <memory>
#include <iostream>

static char buffer[32768];
static char* ptr = &buffer[0];

struct X {
    int a;
    int b;
    void* operator new(size_t size) {
        void* p = ptr;
        ptr += size;
        return p;
    }
    void operator delete(void*) {
        // no need to do anything
    }
};

int main(int argc, char** argv) {

    X* x1 = new X{1,2};
    X* x2 = new X{3,4};

    std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
    std::cout << "xs: " << x2->a << " " << x2->b << std::endl;

    // no leaks since the memory is released when `buffer` is 
    // deallocated. However it is good practice to call the 
    // destructor directly
    x1->~X();
    x2->~X();
}

產生:

Program stdout
x1: 1 2
x2: 3 4

Godbolt: https://godbolt.org/z/jc4r9qbxh

另一種情況是當您將new智能指針一起使用時,如下例所示

#include <cstdint>
#include <memory>
#include <iostream>
#include <boost/intrusive_ptr.hpp>

struct X {
    X(int a_, int b_ ) : a(a_), b(b_){
        std::cout << "Constructor " << this << std::endl;
    }
    ~X() {
        std::cout << "Destructor " << this << std::endl;
    }
    int a;
    int b;
    int count = 0;
};

void intrusive_ptr_add_ref(X* x)
{
    ++x->count;
}

void intrusive_ptr_release(X* x)
{
    if (--x->count == 0)
        delete x;
}

int main(int argc, char** argv) {

    boost::intrusive_ptr<X> x1 = new X{1,2};
    boost::intrusive_ptr<X> x2 = new X{3,4};

    std::cout << "x1: " << x1->a << " " << x1->b << std::endl;
    std::cout << "x2: " << x2->a << " " << x2->b << std::endl;
}

產生:

Constructor 0xb4b2b0
Constructor 0xb4c2e0
x1: 1 2
x2: 3 4
Destructor 0xb4c2e0
Destructor 0xb4b2b0

Godbolt: https://godbolt.org/z/b7MTfazT9

因此,雖然delete是代表調用的,但作為用戶的您不必自己調用delete

另一個用例是為管理對象生命周期的框架創建對象,如Qt

所以答案確實是肯定的,總是在new之后調用delete ,但在行業中有很多情況並不是真的有必要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM