老生常谈,正确使用memset

原文地址:http://blog.csdn.net/my_business/article/details/40537653

前段项目中发现一个问题,程序总是在某个dynamic_cast进行动态转换时出异常,查了半天才发现问题原来是出在memset的使用上,虽然问题本身显而易见,但当处于几十万行代码量级中时,就变得不太那么容易定位了。

本文归纳了下使用memset几个需要注意的地方,虽然内容很简单,但也希望对大家有所帮助。

1. memset是以字节为单位,初始化内存块。

当初始化一个字节单位的数组时,可以用memset把每个数组单元初始化成任何你想要的值,比如,

[cpp] view plain copy

  1. char data[10];
  2. memset(data, 1, sizeof(data));    // right
  3. memset(data, 0, sizeof(data));    // right

而在初始化其他基础类型时,则需要注意,比如,

[cpp] view plain copy

  1. int data[10];
  2. memset(data, 0, sizeof(data));    // right
  3. memset(data, -1, sizeof(data));    // right
  4. memset(data, 1, sizeof(data));    // wrong, data[x] would be 0x0101 instead of 1

2. 当结构体类型中包含指针时,在使用memset初始化时需要小心。

比如如下代码中,

[cpp] view plain copy

  1. struct Parameters {
  2. int x;
  3. int* p_x;
  4. };
  5. Parameters par;
  6. par.p_x = new int[10];
  7. memset(&par, 0, sizeof(par));

当memset初始化时,并不会初始化p_x指向的int数组单元的值,而会把已经分配过内存的p_x指针本身设置为0,造成内存泄漏。同理,对std::vector等数据类型,显而易见也是不应该使用memset来初始化的。

3. 当结构体或类的本身或其基类中存在虚函数时,也需要谨慎使用memset。

这个问题就是在开头项目中发现的问题,如下代码中,

[cpp] view plain copy

  1. class BaseParameters
  2. {
  3. public:
  4. virtual void reset() {}
  5. };
  6. class MyParameters : public BaseParameters
  7. {
  8. public:
  9. int data[3];
  10. int buf[3];
  11. };
  12. MyParameters my_pars;
  13. memset(&my_pars, 0, sizeof(my_pars));
  14. BaseParameters* pars = &my_pars;
  15. //......
  16. MyParameters* my = dynamic_cast<MyParameters*>(pars);

程序运行到dynamic_cast时发生异常。原因其实也很容易发现,我们的目的是为了初始化数据结构MyParameters里的data和buf,正常来说需要初始化的内存空间是sizeof(int) * 3 * 2 = 24字节,但是使用memset直接初始化MyParameters类型的数据结构时,sizeof(my_pars)却是28字节,因为为了实现多态机制,C++对有虚函数的对象会包含一个指向虚函数表(V-Table)的指针,当使用memset时,会把该虚函数表的指针也初始化为0,而dynamic_cast也使用RTTI技术,运行时会使用到V-Table,可此时由于与V-Table的链接已经被破坏,导致程序发生异常。

时间: 2024-08-06 03:38:51

老生常谈,正确使用memset的相关文章

程序转化语意学

    #include "X.h" X foo() { X xx; // -- return xx; } ① 每次foo()被调用,就传回xx的值 ② 如果class X定义了一个拷贝构造函数,那么当foo()被调用时,保证该拷贝构造函数也会被调用 第一个假设的真实性,必须视class X如何定义,第二个假设的真实性虽然也有部分必须视class X如何定义而定,但主要还是要看你的C++ 编译器所提供的进取性优化程度而定.你甚至可以假设在一个高品质的C++ 编译器中,上述两点对于cla

[转]《深度探索C++对象模型》读书笔记[一]

前 言 Stanley B.Lippman1.   任何对象模型都需要的三种转换风味: ü        与编译器息息相关的转换 ü        语言语义转换 ü        程序代码和对象模型的转换 2.   C++对象模型的两种解释 ü        语言中直接支持面向对象程序设计的部分 ü        对于各种支持的底层实现机制 3.   C++ class的完整virtual functions在编译时期就固定下来了,程序员没有办法在执行期动态增加或取代其中某一个.这使得虚拟函数调

c语言学习目标

(1)数据结构.算法的概念和作用 结构化程序设计的方法.三种基本结构程序流程图和 N-S流程图 (2)C程序的一些特点.标识符和关键字的概念.编译. 链接和运行的概念及应用C程序开发流程. 学会至少一种环境下的 C程序开发 (3)常量.变量的概念和使用如何声明和定义变量printf函数和scanf函数的使用 (4)整型.字符型.浮点型数据类型的使用使用printf函数和scanf函数处理各种类型致据使用typedef自定义数据类型限定词const 和 volatile的使用 (5)表达式和语句的

C++对象模型——程序转化语意学(第二章)

2.3    程序转化语意学 (Program Transformation Semantics) 如下程序片段所示: #include "X.h" X foo() { X xx; return xx; } 看到这个代码,可能做出以下假设: 1.    每次foo()被调用,就传回xx的值 2.    如果 class X定义了一个copy constructor,那么当foo()被调用时,保证该copy constructor也会被调用. 第一个假设的真实性,必须视 class X如

UVA 10603 Fill(正确代码尽管非常搓,网上很多代码都不能AC)

题目链接:option=com_onlinejudge&Itemid=8&page=show_problem&problem=1544">click here~ 此题我预计是加强过数据,在我纠结了非常久的时候我交了好几份网上的代码不是WA就是TLE.在我非常迷茫的时候我又交了一份,AC了(尽管我用随机数据找到了他代码一个不能过的数据). 给了我信心.然后我拿他的代码用随机数跟我的代码进行測试.再用FC找不同..发现了一个致命的错误.一般来说,BFS或者DFS都是须要

C++:MEMSET的大坑三两事

之前写了一题费用流,竟然硬是在写SPFA时为DIS数组赋初始值用了MEMSET数组QAQ 调试了很久也没有弄明白自己是卡在那里了,,,感觉被自己蠢哭了QWQ 错误的姿势!! #include <cstring> #include <iostream> #include <cstdio> using namespace std; const int INF = 0x3f3f3f; int dis[50005]; int main() { memset(dis,INF,si

机器人程序设计——之如何正确入门ROS | 硬创公开课(附视频/PPT)【转】

转自:http://blog.exbot.net/archives/2966 导语:本期公开课面向想入手ROS却又不知从何下手的小伙伴,为大家梳理好学习思路. ROS和Android一样是开源的,功能上也是相差无几,它可以提供硬件抽象,底层设备控制,常用功能实现,进程间消息以及数据包管理.其独特之处在于,能够支持多种语言,如C++.Python.Octave和LISP,甚至支持多种语言混合使用,这可以简化开发者的工作.因为它是基于Linux的系统,其可靠性也会更高,体积可以做到更小,适合嵌入式设

一个关于UDP socket服务端接收长度不正确的问题

最近项目需要实现一个通过UDP协议和远端服务平台通讯的需求,简要描述如下: 本端为嵌入式linux路由器(udp客户端,linux C编码),远端为租用的阿里云服务器(udp服务端,java编码), 通信协议为UDP,本端会定时向远端服务器发送消息. 在实现和调试过程中发现一个问题: 1)将远端服务程序放在实验室pc机上调试没有问题,即"路由器-PC"交互正常. 2)将远端服务程序放至阿里云服务器上运行,结果服务端收到的udp消息会多出4个字节,偶尔还会多出6个,多出的字节是 EF B

memset库函数

头文件:#include <string.h> 定义函数:void * memset(void *s, int c, size_t n); 函数说明:memset()会将参数s 所指的内存区域前n 个字节以参数c 填入,然后返回指向s 的指针.在编写程序时,若需要将某一数组作初始化,memset()会相当方便. 返回值:返回指向s 的指针. 附加说明:参数 c 虽声明为int,但必须是unsigned char,所以范围在0 到255 之间. 常用内存空间的初始化. 1.初始化字符数组(常用)