2017-09-14 70 views
1

我一直在閱讀有關C++指針的各種問題和答案,但我仍然基本上不理解某些東西。C++在指針範圍結束後訪問堆上的對象

我讀過,指針允許動態內存分配,通過實際上刪除一個對象,直到明確告訴這樣做。這我明白了,但我不明白的是,堆的對象在其指針的作用域結束之後再次被引用。

查看下面的代碼。

{ 
    myClass* x = new myClass(); 
} 
// How to access the object that x points to here? 

據我所知,在範圍的端部,x(指針本身)不再存在,但對象(指針被指向)仍然在堆上存在。

我的問題是:如果指向內存中該地址的指針不再存在,內存中的地址又是如何訪問的?

+4

它不是。這被稱爲內存泄漏。 – NathanOliver

+0

那麼如何在這個範圍之外訪問這個地址?我認爲這是動態內存分配的全部要點? – ImaginaryHuman072889

+0

這就是爲什麼最好使用智能指針 –

回答

7

如果指向內存中該地址的指針不再存在,內存中的地址又是如何訪問的?

如果指針值沒有存儲在其他地方,則該對象「泄漏」並變得不可訪問。該對象將繼續存在,直到進程終止,此時操作系統將回收該對象所使用的內存。

我不明白的是堆棧上的對象在它的指針範圍結束後再次被引用。

該指針必須複製到其他地方。例如,你可能把指針變成矢量或局部指針之前的地圖超出範圍,則該對象仍然可以通過存儲在矢量/圖指針訪問:

int main() { 
    std::vector<myClass *> objects; 

    { 
     myClass *x = new myClass(); 
     objects.push_back(x); 
    } 

    // The heap-allocated object can be accessed through objects[0] now 
    objects[0]->doSomething(); 

    // Don't forget to clean up (or use smart pointers) 
    for (auto i : objects) { delete i; } 

    return 0; 
} 

注意,是非常有用的學習如何學習C++時使用的原始指針,但在某些時候,你應該切換到智能指針像std::unique_ptr,它會自動delete指向的對象爲您提供:

{ 
    std::unique_ptr<myClass> x{new myClass()}; 
} 
// The myClass object has already been deleted by the smart pointer 
+1

「......在學習C++時學習如何使用原始指針非常有用......」:實際上,如果我正在爲初學者教C++,我可能根本不會提到原始的'new' /'delete',直到非常高級級別,甚至延遲智能指針和「觀察指針」,直到真正需要它們(例如,多態對象向量,自定義遞歸數據結構)。最好讓學生養成將容器直接作爲類的成員的習慣,而不是做不必要的動態分配。 –

+0

@cdhowie感謝您的解釋。只是爲了澄清,在這個例子中,如果使用了'std :: unique_ptr x {new myClass()};',那麼稍後在你的代碼中[objects]會給出一個錯誤,因爲智能指針會有範圍結束時已刪除該對象,對嗎? – ImaginaryHuman072889

+0

@Peter正確,但應該使用'std :: vector >'。然後,你可以移動構建矢量中的unique_ptr,它將從本地'x'轉移所有權。然後'x'將指向'nullptr','objects [0]'將擁有這個分配。當矢量被銷燬時,它將銷燬它所包含的所有'unique_ptr'對象,這又會破壞'myClass'對象。 – cdhowie

0

在這裏你可以找到一個小例子來說明(1)沒有正確刪除的分配,(2)正確刪除的分配和(3)使用智能指針進行分配,當超出範圍時刪除自身。只需運行該程序即可看到第一個示例泄漏內存。

#include <iostream> 
#include <memory> 

class A 
{ 
    public: 
     A(std::string name) : name_(name) 
     { 
      std::cout << "My name is " << name_ << ", and I make mess...\n"; 
     } 
     ~A() 
     { 
      std::cout << "My name is " << name_ << ", and I clean up...\n"; 
     } 
    private: 
     std::string name_; 
}; 

int main() 
{ 
    // 1. Leaks. 
    A* a0; 
    a0 = new A("a0"); 

    // 2. Does not leak. 
    A* a1; 
    a1 = new A("a1"); 
    delete a1; 

    // 3. Does not leak. 
    std::unique_ptr<A> a2 = std::make_unique<A>("a2"); 

    return 0; 
}