Posts Tagged ‘Cpp’

November 24, 2013

  上文书介绍了 C++11 中的右值引用及其应用:移动语义和完美转发。本文介绍另外一个应用广泛的特性,变参模板。变参模板允许模板使用个数可变的参数类型来声明模板,包括类模板和函数模板。

Tags: . 1,157 views
November 23, 2013

  C++11 引入的新特性中,除了并发内存模型和相关设施,这些高帅富之外,最引人入胜且接地气的特性就要属『右值引用』了(rvalue reference)。加入右值引用的动机在于效率:减少不必要的资源拷贝。考虑下面的程序:

1
2
std::vector<string> v;
v.push_back("string");

  向 vector 中添加一个元素,这个动作需要先后调用 string::string(const char*), string::string(const string&), string::~string() 三个函数,涉及两次内存拷贝:第一次使用字面常量 “string” 构造出一个临时对象,第二次使用该临时对象构造出 vector 中的一个新元素,『最后临时对象会发生析构』。

Tags: . 3,702 views
July 5, 2012

  事情是这样的。我们对tair(淘宝的分布式Key/Value系统)动了一次大手术,更换了网络框架,经过长时间的测试/调试,终于完全通过了回归测试。但要打包发布的时候,却发现服务器可以正常启动,但却完全无法接受请求。调试无果,对比打包前后程序的差异,仅在于是否使用-O2选项对程序进行编译优化。
  无头苍蝇一样,Google搜索“gcc optimization problems”,找到StackOverflow上面的这个帖子,“抱着试试看的心态”,在编译选项中加入-fno-strict-aliasing,bingo!
  -fno-strict-aliasing这个选项是做什么的?aliasing又是什么?C和C++的标准给出了说明:

Strict aliasing is an assumption, made by the C (or C++) compiler, that dereferencing pointers to 
objects of different types will never refer to the same memory location (i.e. alias eachother.)
Tags: ,,. 2,708 views
April 24, 2012

这两个程序的输出均是:

pure virtual method called
terminate called without an active exception
Aborted (core dumped)

原因和父类/子类的构造、析构的顺序,以及vtbl的相应变化有关,有兴趣的同学可以研究下。
注:纯虚函数在纯虚类的vtbl中的对应表项为函数__cxa_pure_virtual(),该函数会调用terminate(),后者打印”pure virtual method called”信息后调用abort自杀。

Tags: . 1,303 views
March 15, 2012

  本菜鸟写了一个server,经长时间激烈的测试以后,终于要在测试环境供外部使用了。经过一天激烈的打包,一枚rpm终于诞生了。上传到公司的yum包仓库,当PE同学部署时遇到了问题。程序在启动过程中莫名地core掉了,屡试不爽。使用gdb查看core文件的程序堆栈,发现程序core在了一个我从来没有修改过的类的析构函数中,core的直接原因就是C/C++程序员的老朋友Segmentation fault同学。查看该析构函数,里面只做了两个操作,简单讲,就是释放对象内存的两个delete。其中一个对象是在类的构造函数中创建,另外一个对象是在其他初始化函数startup中创建。析构函数中理所当然地对这两个对象的指针进行判断,非NULL则delete。这个类很特殊,正常情况下需要调用startup进行初始化,然后作为一个持久的对象使用。也可以不进行初始化,调用其他接口,然后销毁。我使用该类的场景就属于后者。在之前的测试过程中,core dump从未发生。

Tags: . 985 views
November 18, 2011

  我们还知道,类的静态成员函数是不需要绑定到特定对象上面的,所以我们就可以将worker声明为静态成员。

1
2
3
4
5
6
7
8
9
10
11
class Thread
{
public:
    static void* worker(void* args) {
        //~ thread execution.
    }
private:
    //~ here some data member.
};
pthread_t tid;
pthread_create(&tid, NULL, &Thread::worker, NULL);

  我们又知道,静态成岩函数是不能’直接’访问类的非静态成员(包括函数),因此,上面代码中worker即使属于class Thread的类域,但却无法访问这个类的成员,这让人十分不爽。哪位大牛说过来着?任何一个复杂的计算机问题,都可以通过中间层来解决。这里也可以建立一个中间层:使用静态成员函数创建线程,给该函数传递某个对象的地址作为参数,在该静态函数中就可以通过所传递对象的使用它的任何成员了。

Tags: ,. 1,602 views
August 7, 2011

使用变参

  C/C++提供了函数的可变参数(variadic)机制,大部分人写的第一个C程序恐怕就是Hello World吧,使用的应该也是printf(“Hello, World\n”)。printf就是一个使用可变参数的典型,它的原型声明为,

int printf(const char *fmt, ...);

  其中返回值为实际输出字符个数,fmt为格式控制字符串,而”…”便声明了一个可变参数,你可以根据传递0个或多个参数给printf。printf内部会根据格式控制串中的格式指定符号(d, f, p等等)来逐个解析通过可变参数传进的实参变量。
  为解析可变参数,C语言提供了一个va_list类型和四个宏,分别是va_start, va_arg, va_end, 和va_copy,这些宏声明在stdarg.h中。

Tags: ,,. 715 views
May 6, 2011

  关于虚函数,需要知道:

  • 多态在C++中借助虚函数实现
  • 多态只在指针或者引用上发生
  • 虚函数机制(通常)借助虚指针vptr支持
  • 虚函数地址保存在虚函数表中
  • 一个类的所有对象共有一张vtbl
  • vtbl由vptr指向,vptr保存在每一个对象中,多继承时可能有多个vptr
  • vptr由构造函数(普通构造/copy构造)在对象初始化时隐式设定
Tags: ,. 746 views
April 25, 2011

  reserve内部是怎么实现的呢?当然是new了。那么在reserve操作,也就是new之后,我们程序是否立即就占用了这些内存呢?这就要看我们这里说的“内存”是什么样的内存了。什么意思呢?我们知道,现代操作系统都采用了虚拟内存的机制,内存占用也就有了虚拟内存(virtual memory)和物理内存(physical memory)之分了。
  我们又知道,Unix/Linux进程的虚拟地址空间被按用途被划分成了内核空间和用户空间。内核空间供操作系统的内核使用,用户空间供用户程序支配。其中用户空间又被划分为若干段,主要包括:代码段(.text),用来存放/映射用户程序的代码;数据段(.data),存放初始化的全局数据或静态数据,这部分在文件系统中也占据磁盘空间;.bss段(一直没找到一个亲切的翻译),存放为初始化的全局或静态数据,在程序加载时分配空间和初始化,这部分空间不占用磁盘空间(当然在可执行文件中要保留其大小);堆栈段,用来保存程序执行时的上下文(局部变量、函数参数和返回地址等),在进程建立时由操作系统分配,空间较小且在运行时不可动态调整,增长方向因机器架构而异,IA上自高地址向下增长,堆栈不占用磁盘空间;堆,供用户在运行时动态地申请和使用,空间较大,未被申请的堆空间不可使用,也不会被映射到物理空间,堆随着用户程序申请向上增长,堆不占用磁盘空间。

Tags: ,,. 549 views
April 10, 2011

  关于C++ STL容器的默认内存管理,需参考allocator。
  关于deque的内存模型及其clear操作,我不甚了了,请参考您使用的标准库的代码。
  若想深入了解STL的实现,侯捷大叔的《STL源码剖析》是不错的入门资料,希望能够拜读。
  C++标准中并未对STL的实现细节做过多规定,因此不同实现的细节和表现可能不同。

  C++很复杂,但也并非无底黑洞。学好C++很难,但这种学习过程也会使你收获颇丰。
  学习任何一种技术,都需要热情、激情和足够的耐心。
  做好一件事,需要激情,同时激情常常来源于做好一件事情的满足感。
  满足感会增强人分享的欲望,分享的欲望也常常会使人具有亲和力和感染力,使人觉得你有激情,反过来更有利于人做好一件事。
  blabla, over~

Tags: ,. 3,415 views
Page 1 of 71234567