標籤:

在C++編程實踐中,我們是否應該放棄使用realloc這個函數?


一般通用容器用不上,因為不知道對象是否 bitwise movable。有些遊戲引擎的容器會通過 traits / tag 標記 bitwise movable,在 insert/erase 時用 memmove(),在 resize 時用 realloc()。另外在一些非通用的數據結構也可使用。


想不出必須要用 realloc 的場合,應該都可以用 vector 替代吧。


先說結論:我以為malloc庫提供的realloc這個函數是有歧義的,在很多場合不應該被使用,當我們分不清正確的使用場合的時候,倒不如直接棄用它。

問題起源於上半年找工作的時候和面試官聊的一個問題:

「vector的容量是如何增長的。」

「先malloc一塊內存,將原來的對象move/cpoy過來,然後析構『老』的對象,最後free掉『老』的內存。」

「你知道realloc這個函數嗎,折騰了一圈,你為什麼不直接使用realloc這個函數。」

「realloc這個函數是C語言提供的,而且有一些歧義,在C++里不建議被使用,例如STLport的std::allocator實現里根本就沒有使用到這個函數。」

「原來是這樣啊!」

這裡malloc對應著std::allocator::allocate,free對應著std::allocator::deallocate,move/cpoy則是用placement new來實現的。

當然不建議使用realloc是我自作聰明說的。

後來我寫JavaScript去了。

半年多沒寫C++了,前兩天看C++ Template的時候,突然想起了這個問題,決定再考慮一下這個問題。

關於realloc這個函數的功能,這裡有說明。

考慮下面的C代碼:

struct Test {
char* arr;
char elems[];
};

struct Test* ptr = (struct Test*)malloc(sizeof(struct Test) + sizeof(char) * 128);
ptr-&>arr = ptr-&>elems;
/* *** */
ptr = (struct Test*)realloc(ptr, sizeof(struct Test) + sizeof(char) * 256);

我覺得這裡的realloc肯定是有問題的,問題的性質和使用memcpy拷貝一個std::string對象一樣,因為缺少了構造對象的過程,說不定std::string中就有一個指針成員變數指向自己或者其他成員變數呢。當然這麼做也有可能是沒問題的,但是誰能完全分得清呢。

說回C++,std::allocator也沒有提供reallocate成員函數,假如它有這個函數,那麼這個函數的實現就需要模板實參類型的move/copy構造函數來保證執行的正確性,而作為一個內存適配器,它根本就沒有責任去做這個事情(雖然我覺得它是可以做到的)。

半年沒碰,真的都忘光了,如果有錯誤的地方,謝謝指正。

後續想到其他的再作補充。

「C++需要不斷地練習。」我決定好好學習並使用C++,爭取明年能用它漲工資。

以上。


面向plain value而不是對象的C介面普遍對C++不是很友好。但是,既然是繼承了的遺產,真的到性能要求苛刻的時候,該用還是得用,留心著就是了。


realloc還是有優點的, 只不過C++里對象拷貝的方式限制了它的使用,

怕出問題不用, 當然也行.

但是想用也是可以的,C++里也經常用到trivially_copyable的對象,你把針對trivially的對象容器

裡面封裝realloc,內部使用static_assert保證安全,然後使勁用,完全沒問題.


即使是自己寫reallocate的時候..其實也是...deallocate原來的 allocate新的

這就是reallocate


realloc - cppreference.com

VC 里的realloc

realloc比malloc+copy+free的最大區別在於當內存足夠時,有可能在原來的內存上直接expand,不改變原來的ptr,也不需要拷貝內存,少了內存碎片,而這就給了程序的優化機會。

理論上來說,你對內存分配器提供越多的信息,內存分配器便越能為你優化。

典型的vector內存增長,我們實際上想要的是把原來的內存grow到一個新的size,我們其實是不關心現有的ptr是否改變的,而這正是realloc為你提供的優化機會。

如果題主指的C++實踐只是在高層用STL庫的話,那確實不太能接觸到realloc。

而如果開始自己造輪子需要實現一些容器,涉及到內存增長時,那realloc實際上還是挺常用的,用的時候小心點就是了,也不用因噎廢食。


個人經驗:我不認為在C++中有任何場景有必須使用這個函數的必要

至於風險,考慮以下場景:

struct MyType{
int data[20];
int* curEntry;
};
///////////

MyType* ptr = (MyType*)malloc(sizeof(MyType));
curEntry = (ptr-&>data[0]);

當你使用realloc的時候,如何保證curEntry一定指回到正確的位置呢?

對於C++中隨時可能見到的高度封裝/複雜化的實例對象,很難保證不會有類似場景的出現。


用C++14的話,C語言里的大部分玩意兒完全不需要用。


就說一個坑

typedef struct _S {

int a;

std::vector& b;

} ST;

ST* arr = malloc(n * sizeof ST);

// do things with arr

// now need make arr bigger + m* sizeof ST

arr = realloc(arr, (n+m) * sizeof ST);

// do thing again, finished

arr = realloc(arr, (p)*sizeof ST); //p &< (n+m)

// sorry here; 減少的部分結構體中vector所開闢的內存泄露了....


Cpp裡面vector可以取代realloc而且功能更強大方便


從來沒見過這個函數,c++里想必malloc都可以不用吧


推薦閱讀:

初二學生能不能學C++?
visual studio為什麼把很多posix函數標記為deprecated?
長期用 C++ 和 MATLAB 做機器學習的你,有沒有遇到一個讓你相見恨晚的語言或包?
devcpp的ascii碼輸出字元時為什麼和ascii碼錶上的字元不同?
在C++11中,如何將一種編碼的string轉換為另一種編碼的string?

TAG:編程 | CC |