c++11 之变长参数模板

C++ 中可以对函数重载,即同样的函数名字(其实在编译期还是会被生成不同的名字)可以有不同的参数列表,例如 STL 中 string 的构造函数:

string();
string (const string& str);
string (const string& str, size_t pos, size_t len = npos);
string (const char* s);
string (const char* s, size_t n);
...

看上去和 C 中的变长参数有点类似:

void func(int nil, ...);

有点不同的是,C …

阅读全文…

PostgreSQL 笔记

PostgreSQL 是一个采用 BSD 许可证分发的跨平台的对象关系模型数据库,最早可以追溯到 1982 年在伯克利开始的 Ingres 计划。PostgreSQL 出现的时间比 MySQL 要早,之前也听过 PostgreSQL 的大名,不过看到相关的讨论比较少。由于这里的实验需求远未达到两者的极限,所以也没什么评测,网上的评价就不搬运过来了,有兴趣的可以搜一下。这里的实验环境是 Debian 6,PostgreSQL 版本是 9.1。

初始化

不同于 MySQL 在安装的时候会被要求输入 root 的密码,安装 PostgreSQL 的时候什么提示都没有,装完之后也不知道该干嘛……在网上搜了一把,照着参考资料 [1] 操作了一遍,基本算是入门了。

由于没有 root 用户,默认有 root 权限的用户名是 postgres,也有同名的数据库。网上有很多介绍初始化的方法都是新建一个 postgres 的用户,然后切换到该用户登录后再修改密码。但是觉得为了初始化新建一个用户有点小题大作了,于是上网搜了下,发现可以通过修改配置文件达到目的。

首先修改 /etc/postgresql/9.1/main/pg_hba.conf,把其中的

local all postgres 

阅读全文…

B- 树

1972 年 R. Bayer 和 E. McCreight 的论文(参考资料 [1])提出了 B- 树。B- 树是一棵平衡树,与一般的平衡二叉树(AVL,红黑树等)不同的是,B- 树的每个节点最多可以拥有 m(m=2)个元素,(m+1)个子节点,并且所有的叶子节点位于同一层。B- 树的查找和插入的时间复杂度和二叉树一样,都是 O(logn),但因为每个节点保存的元素比较多(一般是几十个到几百个之间),树的高度比一般的二叉树要小很多,访问硬盘次数更少,在数据不能全部加载到内存的时候比一般的二叉树效率要好。

定义

一棵最多有 2n+1 个元素(其中 n= 1)的 B- 树的定义如下(参考资料 [2, 3]):

  • 每个节点最多有 2n+1 个元素;
  • 每个非叶子节点(根节点除外)至少有 n+1 棵子树;
  • 如果根节点不是叶子节点,则至少有 2 棵子树;
  • 一个有 k 棵子树的非叶子节点有

阅读全文…

Linux 异步 IO 之 epoll

epoll 是 Linux 内核在 2.5 引入的一个 I/O 事件通知机制,用来取代旧的 select(2) 和 poll(2)。

select() 的工作模式

从通知机制上说,select() 的方式和 epoll 的方式类似,都是阻塞在某个函数上,如果有指定的 I/O 事件发生的话函数就会返回。这样的通知机制的好处在于,在没有事件发生的时候系统可以去干别的事情。不过 select() 只告诉你有事件发生了,但是没有说清楚是哪些 fd 触发了事件通知,你需要去遍历所有的 fd 来找出哪些真正需要处理。select() 的函数原型如下:

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

fd_set 是一个 …

阅读全文…

使用 C 编写 Lua 模块

Lua 作为一种小巧的语言,一般都是嵌入到 C/C++ 中作为扩展语言,但是也可以作为独立的脚本语言使用,并且可以使用 C/C++ 编写扩展模块。在参考资料 [1] 中有怎样用 C/C++ 编写模块的介绍,但是比较零散,也不是很详细,所以在这里整理一下。

这里使用的 Lua 版本是 5.2.3,系统是 Debian 7。

Hello, world!

不废话,还是先看一下经典的 "Hello, world!" 例子。

#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>

static int l_hello(lua_State* l)
{
    printf("Hello, world!\n");
    return 0;
}

static const 

阅读全文…

sicp 笔记 (11)

第四章习题 4.16 - 4.37 的解答。

E-4.16:

(a) 如果匹配到相应的变量再检查一下变量值是否为“unassigned”。

(define (lookup-variable-value var env)
  (define (env-loop env)
    (define (scan vars vals)
      (cond ((null? vars)
             (env-loop (enclosing-environment env)))
            ((eq? var (car vars))
             (let ((v (car vals)))
               (if (eq? v '*unassigned*)
                 (error 

阅读全文…

关于 so 的一些笔记

现在的程序越来越复杂,由多个模块构成,如果把所有的模块和依赖都编译到一个单一的可执行文件中,不仅文件体积很大,而且也不利于模块更新;而且有些基础模块可以被多个程序共用,没必要各个程序都打包一份,因此就有了动态链接库。顾名思义,动态链接库就是可以动态地进行链接,在程序需要的时候才会进行加载,并且这份代码在内存里是共享的,在 Windows 中叫“Dynamic Link Library”,后缀是 dll,Linux 上叫“Shared Object”,后缀一般是“so”。

Hello, world!

下面是经典的打印“Hello, world!”的例子:

#ifndef __HELLO_H__
#define __HELLO_H__

void print(void);

#endif
/* hello.c */

#include <stdio.h>

void print(void)
{
    printf("Hello, world!\n");
}
/* main.c */

#include "hello.h"

int main(void)
{
    print();

    return 

阅读全文…

sicp 笔记 (10)

第四章习题 4.1 - 4.15 的解答。从本章开始使用 mit-scheme 9.1.1。

E-4.1: 题目的意思是,函数 list-of-values 对参数列表的求值顺序依赖于解析器的实现。如果解析器对参数列表的求值顺序是从右往左的,那么 list-of-values 的求值顺序也是从右往左的,也就是说,对于 list-of-values 中的“(cons ...)”,会先算“(list-of-values (rest-operands ...))”这部分,后算“(eval (first-operand ...))”,也就是从右往左了;如果解析器的求值顺序是从左往右,那么 list-of-values 的求值顺序也是从左往右。

(define (list-of-values-lr exps env) ; evaluates from left to right
  (if (no-operands? exps)
    '()
    (let ((first-value (eval (first-operand 

阅读全文…