ZeroMemory C++ 中 ZeroMemory、memset 危險需慎用
阿新 • • 發佈:2018-11-04
C++ 中 ZeroMemory、memset 危險需慎用
2016年11月28日 14:11:16 閱讀數:491使用C/C++程式設計時,常使用ZeroMemory、memset或 “={0}”來對結構體物件進行初始化或清零。然而這三種方式都有各自的特點,使用時需謹慎,否則容易出現嚴重錯誤,本人今日解決一個導致宕機的bug,查了幾小時,才發現是由同事亂用ZeroMemory所致。於是蒐集資料,撰此文以共勉。
memset
void *memset(void *s,int ch,size_t n); 是由C Run-time Library提供的提供的函式,作用是在一段記憶體塊中填充某個給定的值,它是對較大的結構體或陣列進行清零操作的一種最快方法。由於是語言層面提供,所以可跨平臺使用。參考: http://www.cplusplus.com/reference/cstring/memset/
示例:
- char str[] = "almost every programmer should know memset!";
- memset (str,'-'
- puts (str);
輸出: [cpp] view plain copy
- ------ every programmer should know memset!
ZeroMemory
- #define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
- #define ZeroMemory RtlZeroMemory
由此可見:
- ZeroMemory實際是用memset實現的。
- ZeroMemory只能用於windows平臺。
注意:
ZeroMemory和memset且於清零時,會將結構中所有位元組置0,如果結構體中有虛擬函式或結構體成員中有虛擬函式,則會將虛擬函式指標置0,如果後續程式呼叫虛擬函式,空指標很可能導致程式崩潰!
因此,有虛擬函式或成員中有虛擬函式的結構體初始化,一定要用建構函式來完成。
另外,如果一個類的結構中包含STL模板(Vector、List、Map等等),那麼使用ZeroMemory對這個類的物件中進行清零操作也會引起一系列的崩潰問題(指標指向記憶體錯誤、迭代器越界訪問等)。所以,再次強烈建議:類(class)只使用建構函式進行初始化,不要呼叫ZeroMemory進行清零操作。
示例:
[cpp] view plain copy- #include "stdafx.h"
- #include <Windows.h>
- class Car
- {
- public:
- virtual void Run(){}
- private:
- int m_speed;
- };
- struct SRace
- {
- Car car;
- int dirver;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- SRace race;
- ZeroMemory(&race,sizeof(race));
- // 沒通過虛表指標呼叫,沒事
- race.car.Run();
- Car *pCar = &race.car;
- // __vfptr = 0x00000000,崩潰
- pCar->Run();
- return 0;
- }
={0}
={0}操作是結構體和陣列的一種初始化方式,它是將結構體中基本型別變數賦預設值,當結構體中有非基本型別(例如類物件)時,會編譯錯誤,這也是一種保護。