今天写程序的时候,创建了一个结构体:

struct BufferObj {
char* buf;
int bufLen;
SOCKADDR_STORAGE addr;
int addrLen;
struct BufferObj* next;
};

该结构体有一个next指针,本意是这个指针初始的时候应该为NULL,如果有新的BufferObj添加,这个next指针就会指向这个新添加的BufferObj,其实就是一个链表。

程序中有一个生产者线程使用enqueueBufferObj方法向链表里面添加BufferObj:

void enqueueBufferObj(ConnectionObj* connObj, BufferObj* bufferObj) {
EnterCriticalSection(&connObj->sendRecvQueueCriticalSection); if (connObj->pendingSendHead == NULL) {
connObj->pendingSendHead = connObj->pendingSendTail = bufferObj;
} else { connObj->pendingSendTail->next = bufferObj;
connObj->pendingSendTail = bufferObj;
} LeaveCriticalSection(&connObj->sendRecvQueueCriticalSection);
}

还有一个消费者线程从这个链表里面取BufferObj:

BufferObj* dequeueBufferObj(ConnectionObj* connObj) {
BufferObj* res = NULL; EnterCriticalSection(&connObj->sendRecvQueueCriticalSection); if (connObj->pendingSendTail != NULL) {
res = connObj->pendingSendHead;
connObj->pendingSendHead = connObj->pendingSendHead->next;
if (connObj->pendingSendTail == res) {
connObj->pendingSendTail = NULL;
}
}
LeaveCriticalSection(&connObj->sendRecvQueueCriticalSection);
return res;
}

其中,ConnectionObj结构体如下:

struct ConnectionObj {
SOCKET s;
HANDLE hRecvSemaphore;
struct BufferObj* pendingSendHead;
struct BufferObj* pendingSendTail;
CRITICAL_SECTION sendRecvQueueCriticalSection;
};

刚开始的时候,由于程序中没有显示的将BufferObj的next属性初始化NULL,导致程序运行到enqueueBufferObj方法时总是出现指针违法访问:

connObj->pendingSendTail->next = bufferObj;

上面就是出错的地方。程序中对于ConnectionObj中的pendingSendHead和pendingSendTail都已经显示初始化为NULL了。经过查找发现,是因为程序中没有显式对

BufferObj中next进行NULL初始化,从而当消费者线程从队列中BufferObj之后,会重新对队列头进行初始化,该代码在dequeueBufferObj中:

connObj->pendingSendHead = connObj->pendingSendHead->next;

此时,如果BufferObj中的next显示初始化为了NULL,那么connObj->pendingSendHead的值应该为NULL,但是程序中没有对next进行显式初始化,所以,此时,

connObj->pendingSendHead的值为一个随机值,这导致生产者线程使用enqueueBufferObj在向队列中添加新BufferObj时出错:

if (connObj->pendingSendHead == NULL) {//如果next显式初始化了,这个条件检测应该成立
connObj->pendingSendHead = connObj->pendingSendTail = bufferObj;
} else {//但是由于next没有显示初始化,导致pendingSendHead的值不是NULL,而是一个随机的,因此程序错误的运行到这里,出现上述错误 connObj->pendingSendTail->next = bufferObj;
connObj->pendingSendTail = bufferObj;
}

在简单的程序中,这中错误查找起来可能不是问题,但是如果程序很复杂,查找这种错误就会很浪费时间。因此,为了安全起见,以后对于C++中的结构体,类成员,在使用前,还是先进行初始化后为好。

C++中类成员使用前需要初始化的重要性的更多相关文章

  1. Java中类成员变量初始化顺序

    一. 定义处默认初始化vs构造函数中初始化 java中类成员变量支持在声明处初始化,也可以在构造函数中初始化,那么这两者有什么区别呢?看下面例子 public class FieldsInit { p ...

  2. C++中类成员变量在初始化列表中的初始化顺序

    引子:我们知道,C++中类成员变量的初始化顺序与其在类中的声明顺序是有关的. 先看代码: class TestClass1 { public: TestClass1() { cout << ...

  3. 读书笔记 effective c++ Item4 确保对象被使用前进行初始化

    Item4 确保对象被使用前进行初始化 C++在对象的初始化上是变化无常的,例如看下面的例子: Int x; 在一些上下文中,x保证会被初始化成0,在其他一些情况下却不能够保证.看下面的例子: Cla ...

  4. C++ 成员函数前和函数后加const修饰符区别

    博客转载自: https://www.iteblog.com/archives/214.html 分析以下一段程序,阐述成员函数后缀const 和 成员函数前const 的作用 #include< ...

  5. 【C++】const,static和static const类型成员变量声明及其初始化

    1)const定义的常量在超出其作用域之后其空间会被释放,而static定义的静态常量在函数执行后不会释放其存储空间 void f1() { ; cout<<x<<endl; ...

  6. Delphi XE中类成员的访问权限(新增了strict private和strict protected,还有automated)

    Delphi XE中类成员的访问权限共提供了6个关键词来用于限定访问权限:public.private.protected.published.automated strict private . s ...

  7. 读书笔记 effective c++ Item 4 确保对象被使用前进行初始化

    C++在对象的初始化上是变化无常的,例如看下面的例子: int x; 在一些上下文中,x保证会被初始化成0,在其他一些情况下却不能够保证.看下面的例子: class Point { int x,y; ...

  8. 成员变量和成员函数前加static的作用?

    成员变量和成员函数前加static的作用?答:它们被称为常成员变量和常成员函数,又称为类成员变量和类成员函数.分别用来反映类的状态.比如类成员变量可以用来统计类实例的数量,类成员函数负责这种统计的动作 ...

  9. Delphi字符串与字符数组之间的转换(初始化的重要性)

    紧接着上篇博客讲解的内容: 将Char型数组转换为string类型还有下面的这种方法 但是我在测试的时候遇到了一些问题,并在下面进行了解释和总结 先说出我的总结 其实我们在学习编程的时候(比如我之前学 ...

随机推荐

  1. Spring Test 整合 JUnit 4 使用

    这两天做Web开发,发现通过spring进行对象管理之后,做测试变得复杂了.因为所有的Bean都需要在applicationContext.xml中加载好,之后再通过@Resource去取得.如果每次 ...

  2. CLOUDSTACK接管VCENTER,意外频出,但最终搞定

    没办法,第一次吃螃蟹,总是经常住. 还好,我有一颗不肯媚俗的心~~ 但二级存储,和 存储的性能,也必须纳入考虑范围了.

  3. VS2010中水晶报表应用及实例

    原文:VS2010中水晶报表应用及实例 基本分类如下:第一部分:VS2010简介VS2010是微软的提供的一套完整的开发环境,功能也是相当的大微软宣布了下一代开发工具和平台的正式名称,分别称为“Vis ...

  4. -_-#【Backbone】Router

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 【转】掌握java枚举类型(enum type)

    原文网址:http://iaiai.iteye.com/blog/1843553 1   背景 在java语言中还没有引入枚举类型之前,表示枚举类型的常用模式是声明一组具有int常量.之前我们通常利用 ...

  6. Sql自动生成字母加数字的随机数

    /* select char(65+ceiling(rand()*25)) --随机字母(大写) select char(97+ceiling(rand()*25)) --随机字母(小写) selec ...

  7. 用python爬虫抓站的一些技巧总结

    1. [代码]最基本的抓站     ? 1 2 import urllib2 content = urllib2.urlopen('http://XXXX').read() 2. [代码]使用代理服务 ...

  8. 挂载nfs系统问题之: Root-NFS: Server returned error -13 while mounting

    今天换了个路由器,由于是自动分的IP,现在的IP和之前的不在同一网段.以前是192.168.0.xxx,现在是192.168.1.xxx.本以为将serverip,ipaddr,bootargs这些参 ...

  9. C++ Primer Plus(第6版)中文版——课后练习程序代码

    博客内容经历了一次整理,以前发的博文太散.没什么水准,搞的随笔分类越来越多orz,这次把CPP这本书的课后练习的程序代码放到一起方便查阅与修改..嗯 9.6.1 #ifndef _9..1_H_ #d ...

  10. Hadoop2以来的历次升级(不含2.2.0及以下)

    2015年7月06:release 2.7.1(稳定)请参阅 Hadoop 2.7.1发布说明 对131个bug修复和列表 从先前版本2.7.0补丁. 请看看 2.7.0章节列表的增强功能启用 第一个 ...