ZeroMemory、memset 和“={0}” 用於清零操作的區別

      最近在修改程序問題時,發現一個用ZeroMemory的使用問題。ZeroMemory、memset或 “={0}”來對結構體對象進行初始化或清零。然而這三種方式都有各自的特點,使用時需謹慎,否則容易出現嚴重錯誤。

      ZeroMemory是美國微軟公司的軟件開發包SDK中的一個宏。 其作用是用0來填充一塊內存區域。定義式如下:

#define RtlZeroMemory(Destination,Length) memset((Destination),0,(Length))
#define ZeroMemory RtlZeroMemory

      memset的原型是:

       void *memset(void *s,int ch,size_t n); 是由C Run-time Library提供的提供的函數,作用是在一段內存塊中填充某個給定的值,它是對較大的結構體或數組進行清零操作的一種最快方法。由於是語言層面提供,所以可跨平臺使用。參考:
       http://www.cplusplus.com/reference/cstring/memset/

     可見,ZeroMemory實際是用memset實現的,而且只用於Windows平臺。ZeroMemory和memset且於清零時,會將結構中所有字節置0,如果結構體中有虛函數或結構體成員中有虛函數,則會將虛函數指針置0,如果後續程序調用虛函數,空指針很可能導致程序崩潰!

     因此,有虛函數或成員中有虛函數的結構體初始化,一定要用構造函數來完成。

     另外,如果一個類的結構中包含STL模板(Vector、List、Map等等),那麼使用ZeroMemory對這個類的對象中進行清零操作也會引起一系列的崩潰問題(指針指向內存錯誤、迭代器越界訪問等)。所以,再次強烈建議:類(class)只使用構造函數進行初始化,不要調用ZeroMemory進行清零操作。={0}操作是結構體和數組的一種初始化方式,它是將結構體中基本類型變量賦默認值,當結構體中有非基本類型(例如類對象)時,會編譯錯誤,這也是一種保護。

#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;
}

 

發佈了520 篇原創文章 · 獲贊 1266 · 訪問量 186萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章