存档

文章标签 ‘C’

深入浅出Future Pattern

2013年6月24日 没有评论

前几天看hdfs QJM的代码,里面看到一个ListenableFuture,说实话对于Java,目前我还只是通过看代码,遇到没见过的再去查的方式,也着实是没有时间和精力再去通篇研读诸如《thinking in Java》这样的大砖块了,现在这样的方式,目前来说应该是够用了。重点还是放在系统和业务上,语言本身本不应该成为障碍。言归正传,回到ListenableFuture, 在网上看了一下相关的资料,把它的来龙去脉了解了一下,在这里记录一下。

前面提到的ListenableFuture, 是google开源的自己的Java Library Guava(http://code.google.com/p/guava-libraries/)中的一个模块,它本身是继承是Java的Future。严格来讲,Future是一种Design Pattern, 它本身跟语言是没有关系的。最新的C++11中,也加入了Future的支持,不过笔者以前写C++的时候,C++11还没正式发布,加上它本身也是比较新的,主流的编译器支持的本身也不是很好,因此只是知道它的存在,并没有去研究过它是做什么的,怎么来使用的。接下来,我会通过一些Java的Future的例子,来一步步介绍Future及其用法。

简单来讲,Future是这样一种Pattern: 它本身表示‘将来(future)’,你提交一个异步的任务,比如提交到一个threadpool,与此同时拿到一个Future对象,任务的执行是异步的,这时候你可以去做其它的事情,等到异步任务结束的时候,你可通过前面的Future对象拿到异步执行的任务的结果。下面通过一个简单的例子来直观感受一下Future: 阅读全文…

C++模板类继承中的Name Lookup

2012年6月26日 5 条评论

今天这篇文章说说C++中的模板类继承时的名称(变量/类型)查找(Name Lookup)。普通的继承关系中的Name Lookup对于熟悉C++的同学来说,都是非常直观的,因此在这里就不再赘言。模板类(Template Class)的继承中,由于模板本身特殊性,使其在Name Lookup时,有着一定的特殊性,我们从一个例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template< typename T>
class A
{
protected:
    int m_data;
};
 
template< typename T>
class B : public A< T>
{
public:
    void Test(int t)
    {   
        m_data = t;
    }   
};
 
int main(int argc, char** argv)
{
    B< int> b;
    b.Test();
}

阅读全文…

谈谈程序的封装

2011年12月11日 4 条评论

近半年来,团队加入了不少新同学,陆陆续续也看过不少新同学写的代码,一个比较大的感受是,新同学程序的逻辑上问题不会太大,但是代码的封装方面,还是有明显的不足。具体主要包括以下几个方面,一是命名,包括类、函数、变量等的,一个好的名字,可以让读程序的人一看到它就大概知道它是做什么用的;二是函数、类的划分,哪些实体应该抽象为一个类,这个实体的那些功能该抽象成函数,这是程序设计中最为重要的内容;三是线程安全,在多线程环境下,线程安全是一个很重要的话题,很多时候因为封装的不合理,导致使用上的不方便,更为严重的是造成死锁等的问题。下面就分别从这三个方面,谈一些自己的看法,希望能够对初入职场的新同学有所帮助。

第一个方面是命名,这个是最为基本的内容。可以这样讲,把写程序比做写文章,命名对于程序的作用,就相当于措词对于文章,好的措词对于一篇好的文章的作用,不用我再多说。关于程序中的命名,主要包括三种,一是类型名,二是函数名,三是变量名。类型名在C++中应对的包括class, struct, enum等,它们都是抽象出来的一个实体,因此它们的名字最好是一个名词,或者名词词组,比如PCManager,它是一个PC管理器类型。 阅读全文…

漫话C++0x(六)—- variadic templates

2011年11月20日 3 条评论

熟悉printf/scanf的朋友应该对C/C++中的变参函数不陌生,它可以支持任意个数的参数。模板(template)在C++中的地位相信不用我再多说,但是,一直以来,C++模板不支持变参,这成了模板一个被诟病的地方,在很多使用场景限制了模板的威力。举例来说,同样语义的模板函数,因为参数个数不定,有若干个,这样的场景之下,我们只能通过枚举的方式来实现。这样的方法,一方面使得代码本身不够简洁,另一方面因为枚举只能做到有限个数的参数,还是在一定程度上限制了使用的灵活性。现在,C++0x引入了变参模板,上面讲的问题便迎刃而解了,这对C++程序员朋友们来说是莫大的福音。下面我们先看一个简单的例子,先对变参模板有一个直观的印象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include < iostream>
#include < string>
 
void Print()
{
    std::cout < < "\n";
}
 
template< typename T, typename ... TRest>
void Print(const T& obj, const TRest& ... rest)
{
    std::cout < < obj << " ";
    Print(rest ...);
}
 
int main()
{
    double p = 3.14;
    std::string s("pi");
    Print(p, &p, s, &s);
}

阅读全文…

漫话C++0x(五)—- thread, mutex, condition_variable

2011年11月6日 6 条评论

熟悉C++98的朋友,应该都知道,在C++98中没有thread, mutex, condition_variable这些与concurrency相关的特性支持,如果需要写多线程相关程序,都要借助于不同平台上各自提供的api,这样带来的问题就是程序的跨平台移植性比较差,经常要用一大堆的#ifdef WIN32类似的宏来区分不同的平台,搞得程序很难看。C++0x最原始的初衷之一就是为了让C++的功能更加强大,更加方便使用。现如今硬件如此发达,concurrency在程序设计中已经是司空见惯的事情了,如果C++再不支持这些concurrency相关的特性,就真的out了。现在,C++程序员的福音到了,C++0x提供了对thread, mutex, condition_variable这些concurrency相关特性的支持,以后多线程这一块的代码可以完全跨平台了,而且由于C++0x封装的都比较好,代码写起来也十分简洁。下面开始介绍今天的内容。

  • 1. thread
  • 写过多线程程序的朋友,相信对thread本身都不会陌生,这里不对thread本身做太多的说明,以介绍C++0x中提供的thread的用法为主。请大家先看下面的例子: 阅读全文…

漫话C++0x(四) —- function, bind和lambda

2011年10月23日 4 条评论

本文是C++0x系列的第四篇,主要是内容是C++0x中新增的lambda表达式, function对象和bind机制。之所以把这三块放在一起讲,是因为这三块之间有着非常密切的关系,通过对比学习,加深对这部分内容的理解。在开始之间,首先要讲一个概念,closure(闭包),这个概念是理解lambda的基础。下面我们来看看wikipedia上对于计算机领域的closure的定义:

A closure (also lexical closure, function closure or function value) is a function together with
a referencing environment for the non-local variables of that function.

上面的大义是说,closure是一个函数和它所引用的非本地变量的上下文环境的集合。从定义我们可以得知,closure可以访问在它定义范围之外的变量,也即上面提到的non-local vriables,这就大大增加了它的功力。关于closure的最重要的应用就是回调函数,这也是为什么这里把function, bind和lambda放在一起讲的主要原因,它们三者在使用回调函数的过程中各显神通。下面就为大家一步步接开这三者的神秘面纱。

  • 1. function
  • 我们知道,在C++中,可调用实体主要包括函数,函数指针,函数引用,可以隐式转换为函数指定的对象,或者实现了opetator()的对象(即C++98中的functor)。C++0x中,新增加了一个std::function对象,std::function对象是对C++中现有的可调用实体的一种类型安全的包裹(我们知道像函数指针这类可调用实体,是类型不安全的)。我们来看几个关于function对象的例子: 阅读全文…

    分类: 程序人生 标签: , , , , ,

    漫话C++0x(三)

    2011年9月24日 没有评论

    本文是《漫话C++0x》系列的第三篇,接前面的内容,继续为大家介绍一些C++0x中增加的比较好玩的特性。我们知道变量的初始化在C++中是一个比较重要的话题,好的编程习惯建议大家在声明变量的时候最好初始化,这样可以避免一些不必要的问题。另外,在C++98中,变量的初始化(initialization)和赋值(assignment)是两个比较重要的概念,这里大家可以回顾一下,比如常量只能初始化,不能赋值。

    今天要讲的主要内容就是C++0x中新增加的统一初始化的语法,通过与C++98中的对比,我们来加深对C++0x的理解。下面我们来看一些C++98中初始化的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    /// 各种形式的初始化
    const int x(5);           ///< 直接初始化
    const int y = 5;          ///< copy构造初始化
    int arr[] = {1, 2, 3};    ///< 大括号初始化
    struct Point{int x, y;};
    const Point p = {1, 2};   ///< 大括号初始化
    class PointX
    {
    public:
        PointX(int x, int y);
    private:
        int x, y;
    };
    const PointX px(1, 2);    ///< 构造函数初始化
    std::vector< int> vec(arr, arr+3); ///< 从别的容器初始化

    阅读全文…

    漫话C++0x(二)

    2011年9月17日 9 条评论

    本文是《漫话C++0x》系列的第二篇,从本篇开始,我将正式为大家介绍C++0x新增的特性,帮助大家认识C++0x。由于C++0x增加的特性还是挺多的,限于篇幅原因,每一篇只能介绍大概4、5个特性,所以,要把所有的新特性介绍完,需要好几个篇幅。下面言归正传,开始今天要介绍的内容,首先从大家最常用到的基本特性讲起。

  • 1. auto用来声明变量
  • 大家先看看下面的代码,一个我们比较熟悉的C++98中遍历map的例子:

    1
    2
    3
    4
    5
    
    std::map< std::string, std::vector<int> > mp;
    for (std::map< std::string, std::vector<int> >::iterator i = mp.begin(); i != mp.end(); ++i)
    {
        /// traverse the map
    }

    阅读全文…

    分类: 程序人生 标签: , ,

    漫话C++0x(一)

    2011年9月10日 2 条评论

    关于C++0x,很多朋友可能会感到比较陌生,其实简单来讲,它就是C++语言的一个升级版本,至于为什么叫C++0x,且听我一一说来。在介绍C++0x的由来之前,有必要介绍一下C++语言的发展历史,从一开始到现在,C++大概经历了以下几个比较重要的阶段:

  • 1998: ISO官方发布C++标准,俗称C++98,这是第一个C++的官方正式版本
  • 2003: TC1(Technical Corrigendum 1)发布,俗称C++03, 这个版本可以当成是C++98的一个bugfix版本
  • 2005:TR1(Technical Report 1)发布,TR1是一个新增加的库,增加了大约14种新的组件到C++标准中
  • 2008:新C++标准(C++0x)草案发布,这个主要是以TR1的基础上进行了扩充
  • 2011:C++0x标准通过
  • 阅读全文…

    分类: 程序人生 标签: ,

    C++类型转换(type cast)详解

    2011年8月7日 4 条评论

    在C中,类型转换相对比较简单,直接加括号强制转即可,不过这样做的后果,就是很难保证类型安全,所以,在C++中,虽然还允许C方式的类型转换,但是已经成为deprecated的方式了,良好的C++编程习惯都不推荐使用C方式的类型转换了。C++提供了类型相对安全的转换方式,本文的主要内容,就是介绍C++中的各种类型转换方式,以及各自用在什么样的场合下,有什么需要注意的地方,帮助大家更好的掌握类型转换,更好的驾驭自己的程序。
    dynamic_cast,static_cast, const_cast和reinterpret_cast在C++中被统称为显式类型转换,在介绍它们之前,有必要介绍一下C++的隐式类型转换。隐式转换,就是不需要什么特殊运算符的转换,它是在变量赋值过程中自动发生的。在C++中,允许的隐式转换,主要包括以下两种方式:

  • 1. 基本类型之间的隐式转换
  • 阅读全文…

    谈谈程序的可扩展性

    2011年7月30日 5 条评论

    光阴如棱,写程序也有好几个年头了。几年来,写过不少程序,也读过不少别人写的代码,各种各样、形形色色的都有。刚开始写程序的人,大都是以完成任务为主,以结果为导向的,很少会注重程序,或者说代码本身。随着写过、读过的程序越来越多,对写程序的人来说,完成任务、实现当前功能不是唯一的目标了,如何能在完成当前任务的同时,考虑一下,如果后面还会有其它的需求的话,我们现在的程序能不能在尽量不修改现有代码的前提下,通过增加一些新的代码,来实现需求、完成任务。这就是所谓程序的“可扩展性”。

    为了帮助大家更好的理解,下面看一个例子,来实实在在的体会一下程序的可扩展性。这里首先给出需求:实现一个HtmlParser, 提供解析出页面里所有img链接的功能。

  • 1. 先来看看大家最容易想到的一种实现:
  • 阅读全文…

    分类: 程序人生 标签: , ,

    在C/C++程序中打印当前函数调用栈

    2011年6月11日 没有评论

    前几天帮同事跟踪的一个程序莫名退出,没有core dump(当然ulimit是打开的)的问题。我们知道,正常情况下,如果程序因为某种异常条件退出的话,应该会产生core dump,而如果程序正常退出的话,应该是直接或者间接的调用了exit()相关的函数。基于这个事实,我想到了这样一个办法,在程序开始时,通过系统提供的atexit(),向系统注册一个回调函数,在程序调用exit()退出的时候,这个回调函数就会被调用,然后我们在回调函数中打印出当前的函数调用栈,由此便可以知道exit()是在哪里调用,从而上述问题便迎刃而解了。上述方法用来解决类似问题是非常行之有效的。在上面,我提到了在“回调函数中打印出当前的函数调用栈”,相信细心的朋友应该注意到这个了,本文的主要内容就是详细介绍,如何在程序中打印中当前的函数调用栈。
    我之前写过一篇题目为《介绍几个关于C/C++程序调试的函数》的文章,看到这里,请读者朋友先看一下前面这篇,因为本文是以前面这篇文章为基础的。我正是用了backtrace()和backtrace_symbols()这两个函数实现的,下面是一个简单的例子,通过这个例子我们来介绍具体的方法: 阅读全文…

    手把手教你调试STL容器(下)

    2011年5月16日 1 条评论

    本文是《手把手教你调试STL容器》系列的下篇,阅读本文之前,请先阅读上篇《手把手教你调试STL容器(上)》。上篇中主要介绍了STL中string, vector, list, deque这些基本的容器。本篇将介绍由红黑树实现的map/set/multimap/multiset这些容器,以及由hashtable实现的hash_map/hash_set/hash_multimap/hash_multiset这些容器。

  • 1. 红黑树(Red black tree)
  • 我们知道, STL中的map/set/multimap/multiset,都是由红黑树实现的,因此我们要了解map/set/multimap/multiset这些容器是如何实现的,就首先要了解红黑树的基本组成: 阅读全文…

    手把手教你调试STL容器(上)

    2011年5月3日 3 条评论

    众所周知,调试(Debugging)是每个程序员所要必备的基本的技术素养,尤其是对C/C++的程序员来说。对于在linux下用C/C++开发的朋友,相信对GDB不会陌生,当程序有bug或者是出现core dump的时候,GDB是我们最好的朋友。STL是C++相较于C而言,增加的非常强有力的工具,它从某种程度上把C/C++程序员从繁琐的基本数据结构中解放了出来。不过,STL虽然用起来十分方便,但是,用GDB调试过C/C++程序的朋友都有这样痛苦的经历,在GDB状态下,要知道某个STL对象(比如容器)中的数据内容,并不是那么直接、简单。本文的主要内容就是介绍STL中大家比较常用到的容器的基本组成,帮助大家能够在调试的时候更好的驾驭它们。

  • 1. string
  • string是STL中最为常用的类型,它是模板类basic_string用char类型特化后的结果,下面我们来看一下string类型的基本组成: 阅读全文…

    c++ template特化小trick

    2011年4月11日 1 条评论

    前几天在看boost/asio代码的时候,遇到一个奇怪的语法,后查c++ std文档,发现是template特化过程中一个小小的trick,特做此记录,分享给遇到同样问题的朋友,下面先看例子:
    阅读全文…