[英]What's the smart way to use C++ new operator with a function?
這是一個很長的時間。 我有一個從磁盤加載一些圖像數據的功能。 我用三種不同的方法嘗試過這種方法,其中一種不起作用,我想知道最聰明的方法是什么。
方法1:
我曾經進行過設置,以使加載的數據成為函數的參數,這似乎需要在函數外部為其分配空間,然后將指針傳遞給已分配的空間。 這需要提前知道圖像的大小,因此必須進行輔助功能以首先獲得圖像的寬度和高度。 以下是一個示例。
優點:在調用代碼中更明確地表明正在分配內存,因此應將其刪除。
缺點:需要提前知道圖像大小。
// Data allocated outside the image, allocated space passed to function. This works.
// Notice that width & height are passed to the function.
size=(*width)*(*height);
image = new unsigned char[size];
void read_pgm(unsigned char *image, char *file_name, int width, int height){
// Code to read sizeof(char)*width*height bytes of data from the file into image
}
方法2:
我認為讓函數分配自己的數據會很好,因此我不需要傳遞大小。 如果我嘗試在函數中為其分配空間,則函數結束后似乎丟失了空間。 在以下情況下,函數read_pgm
運行正常,但是如果我隨后嘗試將該數據寫入另一個文件,則代碼將崩潰。
優點:無需提前知道圖像大小,無需在調用代碼中分配數據。
缺點:不起作用。 此外,如果這樣做的話,如果我不清除函數外部的圖像,是否會在循環中反復調用它導致內存泄漏?
// Data allocated inside the image for a pointer passed to the function. This doesn't work.
void read_pgm(unsigned char *image, char *file_name, int *width, int *height){
size=(*width)*(*height);
image = new unsigned char[size];
// Code to read the data from the file into image
}
方法3:
此處,數據再次在函數中分配,但作為返回的項目返回。 這行得通,即我可以將數據寫到另一個圖像上。 我不明白為什么這行得通,而方法2卻行不通。
優點:與方法2相同。
缺點:與方法2相同,但當前可以使用。
// Data allocated in the function, and returned. This works.
unsigned char* read_pgm(char *file_name, int *width, int *height){
// Allocate data for the image
size=(*width)*(*height);
image = new unsigned char[size];
// Code to read the data from the file into image
return image; // Return pointer to the data
}
因此,我的問題是:
在這種情況下,將函數設置為自己分配空間是否更聰明,因此調用代碼不需要提供圖像大小? 還是在函數外部進行分配是更明智的選擇,以提醒您有時需要在圖像上調用delete。 還是我認為需要這樣做是錯誤的? 似乎在循環中調用方法2或方法3會導致內存泄漏。
為什么方法2不起作用?
謝謝。
如果您想知道聰明的方法,那么答案必須是“以上皆非”。 聰明的方法? 使用向量。 那就是它的目的。 因為使用new
直接糟透了。 管理您自己的內存范圍很糟糕。 我們為此提供課程。 而char*
作為字符串呢? 至少使其成為const char*
。 const std::string&
更好。 我還必須問-您要嘗試讀取哪種圖像格式,而不以文件格式存儲圖像的寬度和高度? 在我看來,最好從文件中讀取該文件。
std::vector<unsigned int> void ReadImage(const std::string& filename, int width, int height) {
std::vector<unsigned int> imageData(width * height);
// Read here from filestream
}
std::vector<unsigned int> imageData = ReadImage("ohai.png", 1000, 600);
您需要了解-const正確性,RAII和標准庫。
為了使其正常工作,您必須將引用傳遞給指針
unsigned char * & image
否則,您將分配內存,並且傳遞的指針的COPY指向該內存。 原始指針對象不變。
聽說過智能指針嗎?
智能指針可以用來獨自操縱內存。 如果您出於某些無法解釋的原因而不想使用智能指針,例如偽優化,那么我認為您自己描述了所有方法的優缺點-總是要權衡取舍。 由您決定
方法2不起作用,因為您要按值傳遞指針,並在本地覆蓋該值,因此函數外部的指針值不會更改。 您可以通過按引用傳遞它或將指針傳遞給指針來解決此問題。
至於另一個問題:這實際上只是清楚地記錄誰有責任刪除分配的數據。 (順便說一句:是的,您應該取消分配,否則會泄漏)。 在許多API中,您會在文檔中看到:“調用者有責任刪除此數據”或“調用此其他函數以刪除分配的數據”。
消除這種所有權問題的一種好方法是使用智能指針(如Armen所建議的)。
當前所做的所有操作都會導致內存泄漏,因為您從不會delete[]
任何東西。
首先,是的,使尺寸可變。 其次,返回指向新分配的堆存儲的指針並記住在調用方中將其刪除 ,或者返回一個智能容器對象。
一個std::vector<unsigned char>
會做的很好:
std::vector<unsigned char> get_image(const std::string & filename, size_t & width, size_t & height)
{
// determine width and height
/* ... */
std::vector<unsigned char> result(width * height, 0);
// read into &result[0], vector guarantees contiguous storage
return result;
}
考慮將與讀取和“處理”數據有關的所有功能封裝在一個類中。
它應該在構造函數中將文件路徑作為std :: string。
創建文件句柄,分配內存和讀取然后可以在單獨的函數中完成(類似於Init
)。 這樣,您便可以在知道文件路徑時創建對象,但稍后在實際需要時執行耗時的部分(讀取部分)。
您可以向外部用戶公開任何必要的信息(例如身高或寬度)。
類析構函數將負責關閉文件句柄(如果需要,可以更早完成)並取消分配數據。
您可以在類中使用new和delete,或者更好的是,在類中使用智能指針,而不僅僅是圖像數據部分。 您還可以“在堆棧上”使用它,並在超出范圍時自動調用其析構函數。
“ 2.為什么方法2不起作用?”
因為您要通過副本而不是引用傳遞指針。 您傳入一個指針,然后通過new
調用立即重新初始化該指針指向的位置 。 達到功能范圍后,局部變量image
的壽命以及所有可愛的新存儲所在的位置也將到達。
您真正想做的(在這種情況下)是傳遞對指針的引用或指向指針的指針,以便您可以更改傳遞的參數的值(在本例中為指針),並使更改可見在功能范圍之外。
void read_pgm(unsigned char **image, char *file_name, int *width, int *height)
{
size=(*width)*(*height);
(*image) = new unsigned char[size];
// Code to read the data from the file into image
}
實際上, C ++ FAQBook中有一個非常出色的部分,針對這些問題。
正如您所說,最大的問題是確保以不會泄漏的方式分配內存。 C ++有很多方便的工具可以做到這一點,最明顯的是new
和delete
。
最簡單的方法是在將超出范圍的上下文中為new
分配。 所以...
{
MyData *md = new MyData(args);
doSomething(md);
}
現在,當md超出范圍時,它將自動調用dtor。 現在,這個技巧幾乎可以在任何地方使用。
使用方法2,您按原樣寫對了,它會泄漏內存; 下次執行new
,該上次的引用將丟失,但不會最終確定或銷毀。
一個解決方案是在其他地方顯式調用dtor,即將其刪除。
我懷疑它不起作用的原因是image
是一個指針,這是new想要返回的指針。 但是由於C ++會執行按值調用的指針,因此您將該地址放入堆棧的本地內存中,然后它消失了。
您要么想要**
,要么甚至更好的參考。
第三種解決方案是C ++確實具有指針類型來幫助免費商店管理。 該FAQbook介紹了如何實現引用計數指針在這里 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.