2012-06-15 73 views
1

我有函數返回一個對象,但我很困惑,應該返回對象本身還是一個指向對象的指針?使用指針或不使用它們作爲類引用。有什麼不同?

這裏是我的函數的例子:

CImage CDocument::AddImage(string Name, string fileName) 
{ 
    CImage img = CImage(); 
    img.Name = Name; 
    img.Path = fileName; 
    img.IwImage = Iw2DCreateImage(&fileName[0]); 

    Images.push_back(&img); 

    return img; 
} 

這是正確的或者我應該指針返回對象:正確

CImage * CDocument::AddImage(string Name, string fileName) 
{ 
    CImage * img = new CImage(); 
    img->Name = Name; 
    img->Path = fileName; 
    img->IwImage = Iw2DCreateImage(&fileName[0]); 

    Images.push_back(img); 

    return img; 
} 

儘管最後的代碼不編譯,因爲我得到這個錯誤:

error C2440: 'initializing' : cannot convert from 'CImage' to 'CImage *' 

我認爲這可能是非常簡單的問題。我對C++很陌生,所以對我很感興趣。

+0

沒有看到你的代碼,你應該使Name/Path/etc私有,並在構造函數中賦值。此外,使用'CImage img;'而不是'CImage img = CImage();'。 – Pubby

+0

@Rubby不需要使用new調用CImage的構造函數,並將其創建爲img的實例?它自動發生? – bman

+0

@Dane,是的,你在做什麼*應該*調用一個構造函數,然後調用一個拷貝構造函數來分配它。實際上,它可能不會。 – chris

回答

5

在這段代碼中有很多問題,在C++編碼之間的基本區別在於堆棧分配和堆分配之間。當您執行CImage img = CImage();時,該對象將在堆棧​​上創建。此對象在功能結束時自動銷燬。現在,如果你返回一個指向這個對象的指針,調用者將獲得一個指向無效內存位置的指針,因爲該對象已經被銷燬。你也在將這個對象的地址放入向量中,一旦函數結束,這個地址也會失效。同樣的問題也在fileName也有。

要解決這個問題,需要從堆中分配內存,以便在函數結束時不會銷燬對象。您可以使用C++中的new在堆上分配對象。所以你的代碼將變成CImage* pImage = new CImage();。請注意,在這種情況下,您有責任使用delete來釋放內存。所以你可以改變你的功能,使用這種技術返回CImage*。您也可以將此指針推入矢量Images。請注意,要釋放分配給CImage obects的內存,您需要遍歷Images向量,並在每個指針上顯式調用delete

更好的方法是在這種情況下使用智能指針,例如std::shared_ptr,這將自動爲您管理delete的呼叫。

+0

+1用於指出std :: shared_ptr –

+1

請注意,自由矢量「Images」似乎取得了所創建對象的所有權。 – Pubby

+0

@Pubby:編輯答案。 – Naveen

1

要初始化新指針,您需要使用new關鍵字。

CImage * img = new CImage(); 

這在堆上(存儲器的非局部部分)分配的存儲器的一部分,並創建CImage對象那裏。然後它抓取一個指向該對象的指針並返回它,即使函數離開其當前作用域,也可以訪問該對象。這是你應該做的。

但是,如果您執行CImage img = CImage();,您可能會發現在代碼返回後,您將無法引用CImage對象。這是因爲當你聲明一個本地對象(通過不使用new)時,它存在於堆棧(內存的另一部分)上,並且一旦函數返回就會被銷燬。這意味着即使你有一個指向它的指針,該對象將會消失,所以試圖訪問它會給你一個段錯誤。

3

首先修正這些指針部分:

CImage * img = new CImage(); 

修復編譯器錯誤。

考慮實例壽命。一個類的實例一旦到達其作用域的末尾就會被銷燬 - 這裏是該函數的右括號。

第一個示例將在函數結束時銷燬(並釋放內存)img - 這可能會導致意外的行爲,具體取決於Images.push_back的實現。

對於如果調用代碼看起來像這樣很有可能將要創建的變量的副本返回的實例:

CImage outterImage = myDocument.addImage(...); 

outterImage將最有可能是IMG的一個副本,而不是本身的img。

有關更多詳細信息,請查看C++中的實例生命週期。

相關問題