舞影凌乱

专注C/C++,Linux

统计

留言簿(1)

积分与排名

Linux好站点

Oracle

阅读排行榜

评论排行榜

2010年8月15日 #

一个非常有用的Linux命令--cut

     摘要:   阅读全文

posted @ 2010-08-15 01:11 幽梦新影 阅读(1752) | 评论 (1)编辑 收藏

CentOS常用命令(收藏)

在电脑常用操作中,我们经常会用到CentOS常用命令。所以,我们对一些经常使用又很重要的CentOS常用命令进行了全面的整理。下面,就给大家介绍这些CentOS常用命令。

一:使用CentOS常用命令查看cpu

more /proc/cpuinfo | grep "model name"  
grep "model name" /proc/cpuinfo  
[root@localhost /]# grep "CPU" /proc/cpuinfo  
model name      : Intel(R) Pentium(R) Dual CPU E2180 @ 2.00GHz  
model name      : Intel(R) Pentium(R) Dual CPU E2180 @ 2.00GHz  
如果觉得需要看的更加舒服
grep "model name" /proc/cpuinfo | cut -f2 -d:

二:使用CentOS常用命令查看内存

grep MemTotal /proc/meminfo  grep MemTotal /proc/meminfo | cut -f2 -d:  free -m |grep "Mem" | awk '{print $2}'

三:使用CentOS常用命令查看cpu是32位还是64位

查看CPU位数(32 or 64)
getconf LONG_BIT

四:使用CentOS常用命令查看当前linux的版本

more /etc/redhat-release
cat /etc/redhat-release

五:使用CentOS常用命令查看内核版本

uname -r
uname -a

六:使用CentOS常用命令查看当前时间

date上面已经介绍如何同步时间了

七:使用CentOS常用命令查看硬盘和分区

df -h
fdisk -l
也可以查看分区
du -sh
可以看到全部占用的空间
du /etc -sh
可以看到这个目录的大小

八:使用CentOS常用命令查看安装的软件包

查看系统安装的时候装的软件包
cat -n /root/install.log
more /root/install.log | wc -l
查看现在已经安装了那些软件包
rpm -qa
rpm -qa | wc -l
yum list installed | wc -l
不过很奇怪,我通过rpm,和yum这两种方式查询的安装软件包,数量并不一样。没有找到原因。

九:使用CentOS常用命令查看键盘布局

cat /etc/sysconfig/keyboard
cat /etc/sysconfig/keyboard | grep KEYTABLE | cut -f2 -d=

十:使用CentOS常用命令查看selinux情况

sestatus
sestatus | cut -f2 -d:
cat /etc/sysconfig/selinux

十一:使用CentOS常用命令查看ip,mac地址

在ifcfg-eth0 文件里你可以看到mac,网关等信息。  ifconfig  cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep IPADDR  cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep IPADDR | cut -f2 -d=  ifconfig eth0 |grep "inet addr:" |awk '{print $2}'|cut -c 6-  ifconfig   | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print $1}'  查看网关  cat /etc/sysconfig/network  查看dns  cat /etc/resolv.conf  十二:使用CentOS常用命令查看默认语言
echo $LANG $LANGUAGE
cat /etc/sysconfig/i18n

十二:使用CentOS常用命令查看所属时区和是否使用UTC时间

cat /etc/sysconfig/clock

十三:使用CentOS常用命令查看主机名

hostname
cat /etc/sysconfig/network
修改主机名就是修改这个文件,同时最好也把host文件也修改。

十四:使用CentOS常用命令查看开机运行时间

uptime
09:44:45 up 67 days, 23:32, ...
看来刚才确实是网段的问题,我的机器还是67天前开机的。
#系统资源使用情况

vmstat 1 -S m  procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu------  r b   swpd   free   buff cache   si   so    bi    bo   in   cs us sy id wa st  0 0      0    233    199    778    0    0     4    25    1    1 3 0 96 0 0  0 0      0    233    199    778    0    0     0     0 1029 856 13 1 86 0 0

posted @ 2010-08-15 01:03 幽梦新影 阅读(885) | 评论 (0)编辑 收藏

2010年7月3日 #

Oracle 10G Linux 安装笔记

第一部分 安装linux

    1.  操作系统的安装省略,注意配置图形界面

    2.  验证安装

    通过运行以下命令检查内核版本:

    uname –r

    其他所需程序包的版本(或更高版本):

    gcc-3.2.3-2

    make-3.79

    binutils-2.11

    openmotif-2.2.2-16

    setarch-1.3-1

    compat-db-4.0.14.5

    以上为必需的程序包

    compat-gcc-7.3-2.96.122

    compat-gcc-c++-7.3-2.96.122

    compat-libstdc++-7.3-2.96.122

    compat-libstdc++-devel-7.3-2.96.122

    以上为可选程序包,最好安装上

    要查看系统上安装了这些程序包的哪些版本,以 root 用户身份运行以下命令:

    rpm -q gcc make binutils openmotif setarch compat-db compat-gcc compat-gcc-c++ compat-libstdc++ compat-libstdc++-devel

第二部分:针对 Oracle 配置 Linux

    1.  验证系统要求

    要验证系统是否满足 Oracle 10g 数据库的最低要求,以 root 用户身份登录并运行以下命令。

    要查看可用 RAM 和交换空间大小,运行以下命令:

    grep MemTotal /proc/meminfo

    grep SwapTotal /proc/meminfo

    所需最小 RAM 为 512MB,而所需最小交换空间为 1GB.对于 RAM 小于或等于 2GB 的系统,交换空间应为 RAM 数量的两倍;对于 RAM 大于 2GB 的系统,交换空间应为 RAM 数量的一到两倍。

    Oracle 10g 软件还需要 2.5GB 的可用磁盘空间,而数据库则另需 1.2GB 的可用磁盘空间。/tmp 目录至少需要 400MB 的可用空间。要检查系统上的可用磁盘空间,运行以下命令:

    df –h

    2.  创建 Oracle 组和用户帐户

    接下来,创建用于安装和维护 Oracle 10g 软件的 Linux 组和用户帐户。用户帐户将称为 oracle,而组将称为 oinstall 和 dba.以 root 用户身份执行以下命令:

    /usr/sbin/groupadd oinstall

    /usr/sbin/groupadd dba

    /usr/sbin/useradd -m -g oinstall -G dba oracle

    设置 oracle 帐户的口令:

    passwd oracle

    3.  创建目录

    现在,创建存储 Oracle 10g 软件和数据库文件的目录。本指南在创建目录结构时所用的命名惯例符合最佳灵活结构 (OFA) 规范。有关 OFA 标准的更多信息,请参阅针对 UNIX 系统的 Oracle 数据库 10g 安装指南 的附录 D.

    以下假设在根文件系统中创建目录。这样做是为了简便起见,不建议将其作为通用做法。这些目录通常被创建为单独的文件系统。

    以 root 用户身份执行以下命令:

    mkdir -p /u01/app/oracle

    mkdir -p /u02/oradata

    chown -R oracle:oinstall /u01/app/oracle /u02/oradata

    chmod -R 775 /u01/app/oracle /u02/oradata

    4.  配置 Linux 内核参数

    Linux 内核非常出色。与大多数其他 *NIX 系统不同,Linux 允许在系统启动和运行时修改大多数内核参数。完成内核参数更改后不必重新启动系统。Oracle 数据库 10g 需要以下所示的内核参数设置。其中给出的是最小值,因此如果您的系统使用的值较大,则不要更改它。

    kernel.shmall = 2097152

    kernel.shmmax = 2147483648

    kernel.shmmni = 4096

    kernel.sem = 250 32000 100 128

    fs.file-max = 65536

    net.ipv4.ip_local_port_range = 1024 65000

    如果您正确的安装了linux,且内核参数全部采用默认值,则只需在以 root 用户身份登录后执行下命令。

    cat >> /etc/sysctl.conf <<EOF

    kernel.shmall = 2097152

    kernel.shmmax = 2147483648

    kernel.shmmni = 4096

    kernel.sem = 250 32000 100 128

    fs.file-max = 65536

    net.ipv4.ip_local_port_range = 1024 65000

    EOF

    /sbin/sysctl –p

    以 root 用户身份运行以下命令来验证您的设置:

    /sbin/sysctl -a | grep shm

    /sbin/sysctl -a | grep sem

    /sbin/sysctl -a | grep file-max

    /sbin/sysctl -a | grep ip_local_port_range

    如果系统的参数设置的比上述参数值小,则编辑 /etc/sysctl.conf 文件,添加或更改这些参数。完成后,运行以下命令激活更改:

    /sbin/sysctl –p

    5.  为 oracle 用户设置 Shell 限制

    Oracle 建议对每个 Linux 帐户可以使用的进程数和打开的文件数设置限制。要进行这些更改,以 root 用户的身份执行下列命令:

    cat >> /etc/security/limits.conf <<EOF

    oracle               soft    nproc   2047

    oracle               hard    nproc   16384

    oracle               soft    nofile  1024

    oracle               hard    nofile  65536

    EOF

    cat >> /etc/pam.d/login <<EOF

    session    required     /lib/security/pam_limits.so

    EOF

    cat >> /etc/profile <<EOF

    if [ \$USER = "oracle" ]; then

    if [ \$SHELL = "/bin/ksh" ]; then

    ulimit -p 16384

    ulimit -n 65536

    else

    ulimit -u 16384 -n 65536

    fi

    umask 022

    fi

    EOF

    cat >> /etc/csh.login <<EOF

    if ( \$USER == "oracle" ) then

    limit maxproc 16384

    limit descriptors 65536

    umask 022

    endif

    EOF

    6.  oracle 用户的环境变量

    要使用 Oracle 产品,应该或必须设置几个环境变量。对于数据库服务器,建议设置以下环境变量:

    ORACLE_BASE

    ORACLE_HOME

    ORACLE_SID

    PATH

    如果您在同一服务器上安装了多个 Oracle 产品或数据库,则 ORACLE_HOME、ORACLE_SID 和 PATH 变量可能会更改。ORACLE_BASE 变量不应更改,并可以在需要时在您的登录配置文件中设置它。Oracle 提供了一个称作 oraenv 的实用程序来设置其他变量。

    以 oracle 身份登录,并通过在 .bash_profile中添加以下行:

    TMP=/tmp;

    export TMP

    TMPDIR=$TMP;

    export TMPDIR

    ORACLE_BASE=/u01/app/oracle;

    export ORACLE_BASE

    ORACLE_HOME=$ORACLE_BASE/oracle/product/10.2.0/db_1;

    export ORACLE_HOME

    ORACLE_SID=mydb;

    export ORACLE_SID

    ORACLE_TERM=xterm;

    export ORACLE_TERM

    PATH=/usr/sbin:$PATH;

    export PATH

    PATH=$ORACLE_HOME/bin:$PATH;

    export PATH

    LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib;

    export LD_LIBRARY_PATH

    CLASSPATH=$ORACLE_HOME/JRE:$ORACLE_HOME/jlib:$ORACLE_HOME/rdbms/jlib;

    export CLASSPATH

    NLS_LANG="Simplified Chinese_china".ZHS16GBK;

    export NLS_LANG

    此更改将在您下次登录到 oracle 帐户时生效。

  第三部分:安装 Oracle

    1.安装软件

    使用 oracle 帐户登录。

    将目录更改为 Oracle 10g 软件解压缩到的位置。

    启动 Oracle 通用安装程序。

    $ ./runInstaller

    1)欢迎

    Ø         单击 Next.

    2)指定清单目录和证书

    Ø         如果您一直在依循本指南中的步骤,则使用默认值即可。否则,编辑清单目录的路径,以指向正确目录。

    Ø         操作系统组名称应为 oinstall.

    3)如果这是首次在此机器上安装 Oracle,则您将收到一个弹出窗口,提示需要以 root 用户身份运行 orainstRoot.sh 脚本。以 root 用户身份登录,更改到窗口中指定的目录,执行该脚本,然后继续操作。

    4)指定文件位置

    Ø         如果您一直在依循本指南中的步骤,则使用默认值即可。否则,在继续操作前确保源路径和目标路径正确。

    5)选择安装类型

    Ø         接受默认值 Enterprise Edition.

    6)与特定产品相关的先决条件的检查

    Ø         如果您一直在依循本指南中的步骤,则所有检查都应顺利通过。如果一个或多个检查失败,则在继续操作前纠正该问题。

    7)选择数据库配置

    Ø         接受默认值 Create a starter database 和 General Purpose.

    8)指定数据库配置选项

    Ø         输入数据库的全局数据库名称。该名称应包含 ORACLE_SID 和服务器域名(例如,demo1.orademo.org,其中 demo1 是 ORACLE_SID,orademo.org 是域名)。

    Ø         输入全局数据库名称时,SID 框将自动填充。

    Ø         接受默认的数据库字符集。

    Ø         选择 Create database with sample schemas.

    9)选择数据库管理选项

    Ø         选择 Use Database Control for Database Management.

    10)指定数据库文件存储选项

    Ø         选择 File System,然后输入数据库文件要使用的路径名(在本例中为 /u02/oradata)。

    11)指定备份和恢复选项

    Ø          选择 Do not enable Automated backups.

    12)指定数据库模式口令

    Ø         选择 Use the same password for all the accounts.

    Ø         选择一个口令,然后输入两次进行确认。

    13)摘要

    Ø         显示已安装产品的摘要。

    单击 Install.

posted @ 2010-07-03 00:40 幽梦新影 阅读(596) | 评论 (0)编辑 收藏

Oracle 语句大全

     摘要: 1. Oracle安装完成后的初始口令?  internal/oracle   sys/change_on_install   system/manager   scott/tiger   sysman/oem_temp2. ORACLE9IAS WEB CACHE的初始默认用户和密码? administrator/administrat...  阅读全文

posted @ 2010-07-03 00:38 幽梦新影 阅读(1060) | 评论 (0)编辑 收藏

2010年6月24日 #

中国佛学66句震撼世界的禅语

1.人之所以痛苦,在于追求错误的东西。
2.如果你不给自己烦恼,别人也永远不可能给你烦恼。因为你自己的内心,你放不下。
3.你永远要感谢给你逆境的众生。
4.你永远要宽恕众生,不论他有多坏,甚至他伤害过你,你一定要放下,才能得到真正的快乐。
5.当你快乐时,你要想这快乐不是永恒的。当你痛苦时,你要想这痛苦也不是永恒的。
6.今日的执著,会造成明日的后悔。
7.你可以拥有爱,但不要执著,因为分离是必然的。
8.不要浪费你的生命在你一定会后悔的地方上。
9.你什么时候放下,什么时候就没有烦恼。
10.每一种创伤,都是一种成熟。
11.狂妄的人有救,自卑的人没有救,认识自己,降伏自己,改变自己,才能改变别人。
12.你不要一直不满人家,你应该一直检讨自己才对。不满人家,是苦了你自己。
13.一个人如果不能从内心去原谅别人,那他就永远不会心安理得。
14.心中装满着自己的看法与想法的人,永远听不见别人的心声。
15.毁灭人只要一句话,培植一个人却要千句话,请你多口下留情。
16.根本不必回头去看咒骂你的人是谁?如果有一条疯狗咬你一口,难道你也要趴下去反咬他一口吗?
17.永远不要浪费你的一分一秒,去想任何不喜欢你的人。
18.请你用慈悲心和温和的态度,把你的不满与委屈说出来,别人就容易接受。
19.同样的瓶子,你为什么要装毒药呢?同样的心里,你为什么要充满着烦恼呢?
20.得不到的东西,我们会一直以为他是美好的,那是因为你对他了解太少,没有时间与他相处在一起。当有一天,你深入了解后,你会发现原不是你想像中的那么美好。
21.活着一天,就是有福气,就该珍惜。当我哭泣我没有鞋子穿的时候,我发现有人却没有脚。
22.多一分心力去注意别人,就少一分心力反省自己,你懂吗?
23.憎恨别人对自己是一种很大的损失。
24.每一个人都拥有生命,但并非每个人都懂得生命,乃至于珍惜生命。不了解生命的人,生命对他来说,是一种惩罚。
25.情执是苦恼的原因,放下情执,你才能得到自在
26.不要太肯定自己的看法,这样子比较少后悔。
27.当你对自己诚实的时候,世界上没有人能够欺骗得了你。
28.用伤害别人的手段来掩饰自己缺点的人,是可耻的。
29.默默的关怀与祝福别人,那是一种无形的布施。
30.不要刻意去猜测他人的想法,如果你没有智慧与经验的正确判断,通常都会有错误的。
31.要了解一个人,只需要看他的出发点与目的地是否相同,就可以知道他是否真心的。
32.人生的真理,只是藏在平淡无味之中。
33.不洗澡的人,硬擦香水是不会香的。名声与尊贵,是来自于真才实学的。有德自然香。
34.时间总会过去的,让时间流走你的烦恼吧!
35.你硬要把单纯的事情看得很严重,那样子你会很痛苦。
36.永远扭曲别人善意的人,无药可救。
37.说一句谎话,要编造十句谎话来弥补,何苦呢?
38.白白的过一天,无所事事,就像犯了窃盗罪一样
39.广结众缘,就是不要去伤害任何一个人。
40.沉默是毁谤最好的答覆。
41.对人恭敬,就是在庄严你自己。
42.拥有一颗无私的爱心,便拥有了一切。
43.来是偶然的,走是必然的。所以你必须,随缘不变,不变随缘。
44.慈悲是你最好的武器。
45.只要面对现实,你才能超越现实。
46.良心是每一个人最公正的审判官,你骗得了别人,却永远骗不了你自己的良心。
47.不懂得自爱的人,是没有能力去爱别人的。
48.有时候我们要冷静问问自已,我们在追求什么?我们活着为了什么?
49.不要因为小小的争执,远离了你至亲的好友,也不要因为小小的怨恨,忘记了别人的大恩。
50.感谢上苍我所拥有的,感谢上苍我所没有的。
51.凡是能站在别人的角度为他人着想,这个就是慈悲。
52.说话不要有攻击性,不要有杀伤力,不夸已能,不扬人恶,自然能化敌为友。
53.诚实的面对你内心的矛盾和污点,不要欺骗你自己。
54.因果不曾亏欠过我们什么,所以请不要抱怨。
55.大多数的人一辈子只做了三件事;自欺、欺人、被人欺。
56.心是最大的骗子,别人能骗你一时,而它却会骗你一辈子
57.只要自觉心安,东西南北都好。如有一人未度,切莫自己逃了。
58.当你手中抓住一件东西不放时,你只能拥有这件东西,如果你肯放手,你就有机会选择别的。人的心若死执自己的观念,不肯放下,那么他的智慧也只能达到某种程度而已
59.如果你能够平平安安的渡过一天,那就是一种福气了。多少人在今天已经见不到明天的太阳,多少人在今天已经成了残废,多少人在今天已经失去了自由,多少人在今天已经家破人亡。
60.你有你的生命观,我有我的生命观,我不干涉你。只要我能,我就感化你。如果不能,那我就认命。
61.你希望掌握永恒,那你必须控制现在。
62.恶口永远不要出自于我们的口中,不管他有多坏,有多恶。你愈骂他,你的心就被污染了,你要想,他就是你的善知识。
63.别人可以违背因果,别人可以害我们,打我们,毁谤我们。可是我们不能因此而憎恨别人,为什么?我们一定要保有一颗完整的本性和一颗清净的心。
64.如果一个人没有苦难的感受,就不容易对他人给予同情。你要学救苦救难的精神,就得先受苦受难。
65.世界原本就不是属于你,因此你用不着抛弃,要抛弃的是一切的执著。万物皆为我所用,但非我所属。
66.虽然我们不能改变周遭的世界,我们就只好改变自己,用慈悲心和智慧心来面对这一切。

posted @ 2010-06-24 21:18 幽梦新影 阅读(329) | 评论 (0)编辑 收藏

2010年6月23日 #

STL vector 容器介绍

介绍

这篇文章的目的是为了介绍std::vector,如何恰当地使用它们的成员函数等操作。本文中还讨论了条件函数和函数指针在迭代算法中使用,如在remove_if()for_each()中的使用。通过阅读这篇文章读者应该能够有效地使用vector容器,而且应该不会再去使用C类型的动态数组了。

 

Vector总览

vectorC++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。

为了可以使用vector,必须在你的头文件中包含下面的代码:

#include <vector>

 

vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:

using std::vector;

vector<int> vInts;

 

或者连在一起,使用全名:

std::vector<int> vInts;

 

建议使用全局的命名域方式:

using namespace std;

 

在后面的操作中全局的命名域方式会造成一些问题。vector容器提供了很多接口,在下面的表中列出vector的成员函数和操作。

 

Vector成员函数

函数

表述

c.assign(beg,end)

c.assign(n,elem)

[beg; end)区间中的数据赋值给c

nelem的拷贝赋值给c

c.at(idx)

传回索引idx所指的数据,如果idx越界,抛出out_of_range

c.back()

传回最后一个数据,不检查这个数据是否存在。

c.begin()

传回迭代器重的可一个数据。

c.capacity()

返回容器中数据个数。

c.clear()

移除容器中所有数据。

c.empty()

判断容器是否为空。

c.end()

指向迭代器中的最后一个数据地址。

c.erase(pos)

c.erase(beg,end)

删除pos位置的数据,传回下一个数据的位置。

删除[beg,end)区间的数据,传回下一个数据的位置

c.front()

传回地一个数据。

get_allocator

使用构造函数返回一个拷贝。

c.insert(pos,elem)

c.insert(pos,n,elem)

c.insert(pos,beg,end)

pos位置插入一个elem拷贝,传回新数据位置。

pos位置插入nelem数据。无返回值。

pos位置插入在[beg,end)区间的数据。无返回值。

c.max_size()

返回容器中最大数据的数量。

c.pop_back()

删除最后一个数据。

c.push_back(elem)

在尾部加入一个数据。

c.rbegin()

传回一个逆向队列的第一个数据。

c.rend()

传回一个逆向队列的最后一个数据的下一个位置。

c.resize(num)

重新指定队列的长度。

c.reserve()

保留适当的容量。

c.size()

返回容器中实际数据的个数。

c1.swap(c2)

swap(c1,c2)

c1c2元素互换。

同上操作。

vector<Elem> c

vector <Elem> c1(c2)

vector <Elem> c(n)

vector <Elem> c(n, elem)

vector <Elem> c(beg,end)

c.~ vector <Elem>()

创建一个空的vector

复制一个vector

创建一个vector,含有n个数据,数据均已缺省构造产生

创建一个含有nelem拷贝的vector

创建一个以[beg;end)区间的vector

销毁所有数据,释放内存。

 

Vector操作

函数

描述

operator[]

返回容器中指定位置的一个引用。

 

创建一个vector

vector容器提供了多种创建方法,下面介绍几种常用的。

创建一个Widget类型的空的vector对象:

vector<Widget> vWidgets;

//     ------

//      |

//      |- Since vector is a container, its member functions

//         operate on iterators and the container itself so

//         it can hold objects of any type.

 

创建一个包含500Widget类型数据的vector

vector<Widget> vWidgets(500);

 

创建一个包含500Widget类型数据的vector,并且都初始化为0

vector<Widget> vWidgets(500, Widget(0));

 

创建一个Widget的拷贝:

vector<Widget> vWidgetsFromAnother(vWidgets);

 

vector添加一个数据

vector添加数据的缺省方法是push_back()push_back()函数表示将数据添加到vector的尾部,并按需要来分配内存。例如:向vector<Widget>中添加10个数据,需要如下编写代码:

for(int i= 0;i<10; i++)

    vWidgets.push_back(Widget(i));

 

获取vector中制定位置的数据

很多时候我们不必要知道vector里面有多少数据,vector里面的数据是动态分配的,使用push_back()的一系列分配空间常常决定于文件或一些数据源。如果你想知道vector存放了多少数据,你可以使用empty()。获取vector的大小,可以使用size()。例如,如果你想获取一个vector v的大小,但不知道它是否为空,或者已经包含了数据,如果为空想设置为-1,你可以使用下面的代码实现:

int nSize = v.empty() ? -1 : static_cast<int>(v.size());

 

访问vector中的数据

使用两种方法来访问vector

1、   vector::at()

2、   vector::operator[]

operator[]主要是为了与C语言进行兼容。它可以像C语言数组一样操作。但at()是我们的首选,因为at()进行了边界检查,如果访问超过了vector的范围,将抛出一个例外。由于operator[]容易造成一些错误,所有我们很少用它,下面进行验证一下:

分析下面的代码:

vector<int> v;

v.reserve(10);

 

for(int i=0; i<7; i++)

    v.push_back(i);

 

try

{

 int iVal1 = v[7]; // not bounds checked - will not throw

 int iVal2 = v.at(7); // bounds checked - will throw if out of range

}

catch(const exception& e)

{

 cout << e.what();

}

 

我们使用reserve()分配了10int型的空间,但并不没有初始化。如下图所示:


你可以在这个代码中尝试不同条件,观察它的结果,但是无论何时使用at(),都是正确的。

 

删除vector中的数据

vector能够非常容易地添加数据,也能很方便地取出数据,同样vector提供了erase()pop_back()clear()来删除数据,当你删除数据的时候,你应该知道要删除尾部的数据,或者是删除所有数据,还是个别的数据。在考虑删除等操作之前让我们静下来考虑一下在STL中的一些应用。

 

Remove_if()算法

现在我们考虑操作里面的数据。如果要使用remove_if(),我们需要在头文件中包含如下代码::

#include <algorithm>

 

         Remove_if()有三个参数:

1、   iterator _First:指向第一个数据的迭代指针。

2、   iterator _Last:指向最后一个数据的迭代指针。

3、   predicate _Pred:一个可以对迭代操作的条件函数。

 

条件函数

条件函数是一个按照用户定义的条件返回是或否的结果,是最基本的函数指针,或者是一个函数对象。这个函数对象需要支持所有的函数调用操作,重载operator()()操作。remove_if()是通过unary_function继承下来的,允许传递数据作为条件。

例如,假如你想从一个vector<CString>中删除匹配的数据,如果字串中包含了一个值,从这个值开始,从这个值结束。首先你应该建立一个数据结构来包含这些数据,类似代码如下:

#include <functional>

enum findmodes

{

 FM_INVALID = 0,

 FM_IS,

 FM_STARTSWITH,

 FM_ENDSWITH,

 FM_CONTAINS

};

typedef struct tagFindStr

{

 UINT iMode;

 CString szMatchStr;

} FindStr;

typedef FindStr* LPFINDSTR;

 

然后处理条件判断:

class FindMatchingString

    : public std::unary_function<CString, bool>

{

   

public:

 FindMatchingString(const LPFINDSTR lpFS) : m_lpFS(lpFS) {}

   

 bool operator()(CString& szStringToCompare) const

 {

     bool retVal = false;

 

     switch(m_lpFS->iMode)

     {

     case FM_IS:

       {

         retVal = (szStringToCompare == m_lpFDD->szMatchStr);

         break;

       }

     case FM_STARTSWITH:

       {

         retVal = (szStringToCompare.Left(m_lpFDD->szMatchStr.GetLength())

               == m_lpFDD->szWindowTitle);

         break;

       }

     case FM_ENDSWITH:

       {

         retVal = (szStringToCompare.Right(m_lpFDD->szMatchStr.GetLength())

               == m_lpFDD->szMatchStr);

         break;

       }

     case FM_CONTAINS:

       {

         retVal = (szStringToCompare.Find(m_lpFDD->szMatchStr) != -1);

         break;

       }

     }

       

     return retVal;

 }

       

private:

    LPFINDSTR m_lpFS;

};

 

通过这个操作你可以从vector中有效地删除数据:

// remove all strings containing the value of

// szRemove from vector<CString> vs.

 

FindStr fs;

fs.iMode = FM_CONTAINS;

fs.szMatchStr = szRemove;

 

vs.erase(std::remove_if(vs.begin(), vs.end(), FindMatchingString(&fs)), vs.end());

 

Remove_if()能做什么?

你可能会疑惑,对于上面那个例子在调用remove_if()的时候还要使用erase()呢?这是因为大家并不熟悉STL中的算法。Remove(),remove_if()等所有的移出操作都是建立在一个迭代范围上的,那么不能操作容器中的数据。所以在使用remove_if(),实际上操作的时容器里数据的上面的。思考上面的例子:

1、   szRemove = “o”.

2、   vs见下面图表中的显示。

观察这个结果,我们可以看到remove_if()实际上是根据条件对迭代地址进行了修改,在数据的后面存在一些残余的数据,那些需要删除的数据。剩下的数据的位置可能不是原来的数据,但他们是不知道的。

调用erase()来删除那些残余的数据。注意上面例子中通过erase()删除remove_if()的结果和vs.enc()范围的数据。

 

压缩一个臃肿的vector

很多时候大量的删除数据,或者通过使用reserve(),结果vector的空间远远大于实际需要的。所有需要压缩vector到它实际的大小。resize()能够增加vector的大小。Clear()仅仅能够改变缓存的大小,所有的这些对于vector释放内存等九非常重要了。如何来解决这些问题呢,让我们来操作一下。

我们可以通过一个vector创建另一个vector。让我们看看这将发生什么。假定我们已经有一个vector v,它的内存大小为1000,当我们调用size()的时候,它的大小仅为7。我们浪费了大量的内存。让我们在它的基础上创建一个vector

 

std::vector<CString> vNew(v);

cout << vNew.capacity();

 

vNew.capacity()返回的是7。这说明新创建的只是根据实际大小来分配的空间。现在我们不想释放v,因为我们要在其它地方用到它,我们可以使用swap()vvNew互相交换一下?

 

    vNew.swap(v);

    cout << vNew.capacity();

    cout << v.capacity();

 

有趣的是:vNew.capacity()1000v.capacity()7

现在是达到我的目的了,但是并不是很好的解决方法,我们可以像下面这么写:

 

    std::vector<CString>(v).swap(v);

     

你可以看到我们做了什么?我们创建了一个临时变量代替那个命名的,然后使用swap(),这样我们就去掉了不必要的空间,得到实际大小的v

 

结论

我希望这个文档可以给那些使用STL vector容器的开发者很有价值的参考。我也希望通过阅读这篇文章你可以放心地使用vector来代替C语言中的数据了。

 

参考

Plauger, P.J. Standard C++ Library Reference. February, 2003. MSDN.

Schildt, Herbert. C++ from the Ground Up, Second Edition. Berkeley: 1998.

Sutter, Herb. More Exceptional C++. Indianapolis: 2002.

posted @ 2010-06-23 13:56 幽梦新影 阅读(444) | 评论 (0)编辑 收藏

2010年6月2日 #

C++ STL编程轻松入门

  作为C++标准不可缺少的一部分,STL应该是渗透在C++程序的角角落落里的。STL不是实验室里的宠儿,也不是程序员桌上的摆设,她的激动人心并非昙花一现。本教程旨在传播和普及STL的基础知识,若能借此机会为STL的推广做些力所能及的事情,到也是件让人愉快的事情。 

  1 初识STL:解答一些疑问  1.1 一个最关心的问题:什么是STL科学领域里所常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。这种现象有些类似于Microsoft Visual C++中的MFC(Microsoft Foundation Class Library),或者是Borland C++ Builder中的VCL(Visual Component Library),对于此二者,大家一定不会陌生吧。

  "什么是STL?",假如你对STL还知之甚少,那么我想,你一定很想知道这个问题的答案,坦率地讲,要指望用短短数言将这个问题阐述清楚,也决非易事。因此,如果你在看完本节之后还是觉得似懂非懂,大可不必着急,在阅读了后续内容之后,相信你对STL的认识,将会愈加清晰、准确和完整。不过,上述这番话听起来是否有点像是在为自己糟糕的表达能力开脱罪责呢?:) 

  不知道你是否有过这样的经历。在你准备着手完成数据结构老师所布置的家庭作业时,或者在你为你所负责的某个软件项目中添加一项新功能时,你发现需要用到一个链表(List)或者是映射表(Map)之类的东西,但是手头并没有现成的代码。于是在你开始正式考虑程序功能之前,手工实现List或者Map是不可避免的。于是……,最终你顺利完成了任务。或许此时,作为一个具有较高素养的程序员的你还不肯罢休(或者是一个喜欢偷懒的优等生:),因为你会想到,如果以后还遇到这样的情况怎么办?没有必要再做一遍同样的事情吧! 

  如果说上述这种情形每天都在发生,或许有点夸张。但是,如果说整个软件领域里,数十年来确实都在为了一个目标而奋斗--可复用性(reusability),这看起来似乎并不夸张。从最早的面向过程的函数库,到面向对象的程序设计思想,到各种组件技术(如:COM、EJB),到设计模式(design pattern)等等。而STL也在做着类似的事情,同时在它背后蕴涵着一种新的程序设计思想--泛型化设计(generic programming)。 

  继续上面提到的那个例子,假如你把List或者map完好的保留了下来,正在暗自得意。且慢,如果下一回的List里放的不是浮点数而是整数呢?如果你所实现的Map在效率上总是令你不太满意并且有时还会出些bug呢?你该如何面对这些问题?使用STL是一个不错的选择,确实如此,STL可以漂亮地解决上面提到的这些问题,尽管你还可以寻求其他方法。

 说了半天,到底STL是什么东西呢? 

  STL(Standard Template Library),即标准模板库,是一个具有工业强度的,高效的C++程序库。它被容纳于C++标准程序库(C++ Standard Library)中,是ANSI/ISO C++标准中最新的也是极具革命性的一部分。该库包含了诸多在计算机 

  从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming),引入了诸多新的名词,比如像需求(requirements),概念(concept),模型(model),容器(container),算法(algorithmn),迭代子(iterator)等。与OOP(object-oriented programming)中的多态(polymorphism)一样,泛型也是一种软件的复用技术。 

  从实现层次看,整个STL是以一种类型参数化(type parameterized)的方式实现的,这种方式基于一个在早先C++标准中没有出现的语言特性--模板(template)。如果查阅任何一个版本的STL源代码,你就会发现,模板作为构成整个STL的基石是一件千真万确的事情。除此之外,还有许多C++的新特性为STL的实现提供了方便。 

  不知你对这里一下子冒出这么多术语做何感想,希望不会另你不愉快。假如你对它们之中的大多数不甚了解,敬请放心,在后续内容中将会对这些名词逐一论述。正如开头所提到的。 

  有趣的是,对于STL还有另外一种解释--STepanov & Lee,前者是指Alexander Stepanov,STL的创始人;而后者是Meng Lee,她也是使STL得以推行的功臣,第一个STL成品就是他们合作完成的。这一提法源自1995年3月,Dr.Dobb's Journal特约记者, 著名技术书籍作家Al Stevens对Alexander Stepanov的一篇专访。 

  1.2 追根溯源:STL的历史学院教授David Musser共同开发了一种叫做Tecton的语言。尽管这次尝试最终没有取得实用性的成果,但却给了Stepanov很大的启示。 

  在结识新朋友的时候,大多数人总是忍不住想了解对方的过去。本节将带您简单回顾一下STL的过去。 

  被誉为STL之父的Alexander Stepanov,出生于苏联莫斯科,早在20世纪70年代后半期,他便已经开始考虑,在保证效率的前提下,将算法从诸多具体应用之中抽象出来的可能性,这便是后来泛型化思想的雏形。为了验证自己的思想,他和纽约州立大学教授Deepak Kapur,伦塞里尔技术 

  在随后的几年中,他又和David Musser等人先后用Schema语言(一种Lisp语言的变种)和Ada语言建立了一些大型程序库。这其间,Alexander Stepanov开始意识到,在当时的面向对象程序设计思想中所存在的一些问题,比如抽象数据类型概念所存在的缺陷。Stepanov希望通过对软件领域中各组成部分的分类,逐渐形成一种软件设计的概念性框架。 

  1987年左右,在贝尔实验室工作的Alexander Stepanov开始首次采用C++语言进行泛型软件库的研究。但遗憾的是,当时的C++语言还没有引入模板(template)的语法,现在我们可以清楚的看到,模板概念之于STL实现,是何等重要。是时使然,采用继承机制是别无选择的。尽管如此,Stepanov还是开发出了一个庞大的算法库。与此同时,在与Andrew Koenig(前ISO C++标准化委员会主席)和Bjarne Stroustrup(C++语言的创始人)等顶级大师们的共事过程中,Stepanov开始注意到C/C++语言在实现其泛型思想方面所具有的潜在优势。就拿C/C++中的指针而言,它的灵活与高效运用,使后来的STL在实现泛型化的同时更是保持了高效率。另外,在STL中占据极其重要地位的迭代子概念便是源自于C/C++中原生指针( native pointer)的抽象。

  1988年,Alexander Stepanov开始进入惠普的Palo Alto实验室工作,在随后的4年中,他从事的是有关磁盘驱动器方面的工作。直到1992年,由于参加并主持了实验室主任Bill Worley所建立的一个有关算法的研究项目,才使他重新回到了泛型化算法的研究工作上来。项目自建立之后,参与者从最初的8人逐渐减少,最后只剩下两个人--Stepanove本人和Meng Lee。经过长时间的努力,最终,信念与汗水所换来的是一个包含有大量数据结构和算法部件的庞大运行库。这便是现在的STL的雏形(同时也是STL的一个实现版本--HP STL)。 

  1993年,当时在贝尔实验室的Andrew Koenig看到了Stepanove的研究成果,很是兴奋。在他的鼓励与帮助下,Stepanove于是年9月的圣何塞为ANSI/ISO C++标准委员会做了一个相关演讲(题为"The Science of C++ Programming"),向委员们讲述了其观念。然后又于次年3月,在圣迭戈会议上,向委员会提交了一份建议书,以期使STL成为C++标准库的一部分。尽管这一建议十分庞大,以至于降低了被通过的可能性,但由于其所包含的新思想,投票结果以压倒多数的意见认为推迟对该建议的决定。 

  随后,在众人的帮助之下,包括Bjarne Stroustrup在内,Stepanove又对STL进行了改进。同时加入了一个封装内存模式信息的抽象模块,也就是现在STL中的allocator,它使STL的大部分实现都可以独立于具体的内存模式,从而独立于具体平台。在同年夏季的滑铁卢会议上,委员们以80%赞成,20%反对,最终通过了提案,决定将STL正式纳入C++标准化进程之中,随后STL便被放进了会议的工作文件中。自此,STL终于成为了C++家族中的重要一员。 

  此后,随着C++标准的不断改进,STL也在不断地作着相应的演化。直至1998年,ANSI/ISO C++标准正式定案,STL始终是C++标准中不可或缺的一大部件。 

  1.3 千丝万缕的联系  1.3.1 STL和C++  1.3.2 STL和C++标准函数库1.3.3 STL和GP,GP和OOP   1.4 STL的不同实现版本  1.4.1 HP STL  1.4.2 P.J. Plauger STLhttp://www.dinkumware.comVisualStudiohashset容器。1.4.3 Rouge Wave STLhttp://www.rougewave.com源代码C:Program Files\Borland\Cbuilder6\Include\oldstl)。1.4.4 STLporthttp://www.stlport.org免费下载VC中的STL要快。比Rouge Wave STL更符合标准,也更容易移植。Borland C++ Builder已经在其6.0版中加入了对STLport的支持,它使用的STLport就是4.5版的,C++ Builder 6.0同时还提供了STLport的使用说明。你可以在C++ Builder的Include\Stlport子目录下找到所有头文件(比如:C:\Program Files\Borland\Cbuilder6\Include\Stlport)。1.4.5 SGI STLhttp://www.sgi.com新版本是3.3。 


  在你了解了STL的过去之后,一些名词开始不断在你的大脑中浮现,STL、C++、C++标准函数库、泛型程序设计、面向对象程序设计……,这些概念意味着什么?他们之间的关系又是什么?如果你想了解某些细节,这里也许有你希望得到的答案。 


  没有C++语言就没有STL,这么说毫不为过。一般而言,STL作为一个泛型化的数据结构和算法库,并不牵涉具体语言(当然,在C++里,它被称为STL)。也就是说,如果条件允许,用其他语言也可以实现之。这里所说的条件,主要是指类似于"模板"这样的语法机制。如果你没有略过前一节内容的话,应该可以看到,Alexander Stepanov在选择C++语言作为实现工具之前,早以采用过多种程序设计语言。但是,为什么最终还是C++幸运的承担了这个历史性任务呢?原因不仅在于前述那个条件,还在于C++在某些方面所表现出来的优越特性,比如:高效而灵活的指针。但是如果把C++作为一种OOP(Object-Oriented Programming,面向对象程序设计)语言来看待的话(事实上我们一般都是这么认为的,不是吗?),其功能强大的继承机制却没有给STL的实现帮上多大的忙。在STL的源代码里,并没有太多太复杂的继承关系。继承的思想,甚而面向对象的思想,还不足以实现类似STL这样的泛型库。C++只有在引入了"模板"之后,才直接导致了STL的诞生。这也正是为什么,用其他比C++更纯的面向对象语言无法实现泛型思想的一个重要原因。当然,事情总是在变化之中,像Java在这方面,就是一个很好的例子,jdk1.4中已经加入了泛型的特性。

  此外,STL对于C++的发展,尤其是模板机制,也起到了促进作用。比如:模板函数的偏特化(template function partial specialization),它被用于在特定应用场合,为一般模板函数提供一系列特殊化版本。这一特性是继STL被ANSI/ISO C++标准委员会通过之后,在Bjarne和Stepanov共同商讨之下并由Bjarne向委员会提出建议的,最终该项建议被通过。这使得STL中的一些算法在处理特殊情形时可以选择非一般化的方式,从而保证了执行的效率。 


  STL是最新的C++标准函数库中的一个子集,这个庞大的子集占据了整个库的大约80%的分量。而作为在实现STL过程中扮演关键角色的模板则充斥了几乎整个C++标准函数库。在这里,我们有必要看一看C++标准函数库里包含了哪些内容,其中又有哪些是属于标准模板库(即STL)的。 

  C++标准函数库为C++程序员们提供了一个可扩展的基础性框架。我们从中可以获得极大的便利,同时也可以通过继承现有类,自己编制符合接口规范的容器、算法、迭代子等方式对之进行扩展。它大致包含了如下几个组件: 

  C标准函数库,基本保持了与原有C语言程序库的良好兼容,尽管有些微变化。人们总会忍不住留恋过去的美好岁月,如果你曾经是一个C程序员,对这一点一定体会颇深。或许有一点会让你觉得奇怪,那就是在C++标准库中存在两套C的函数库,一套是带有.h扩展名的(比如),而另一套则没有(比如)。它们确实没有太大的不同。 

  语言支持(language support)部分,包含了一些标准类型的定义以及其他特性的定义,这些内容,被用于标准库的其他地方或是具体的应用程序中。 

  诊断(diagnostics)部分,提供了用于程序诊断和报错的功能,包含了异常处理(exception handling),断言(assertions),错误代码(error number codes)三种方式。 

  通用工具(general utilities)部分,这部分内容为C++标准库的其他部分提供支持,当然你也可以在自己的程序中调用相应功能。比如:动态内存管理工具,日期/时间处理工具。记住,这里的内容也已经被泛化了(即采用了模板机制)。 

  字符串(string)部分,用来代表和处理文本。它提供了足够丰富的功能。事实上,文本是一个string对象,它可以被看作是一个字符序列,字符类型可能是char,或者wchar_t等等。string可以被转换成char*类型,这样便可以和以前所写的C/C++代码和平共处了。因为那时侯除了char*,没有别的。 

  国际化(internationalization)部分,作为OOP特性之一的封装机制在这里扮演着消除文化和地域差异的角色,采用locale和facet可以为程序提供众多国际化支持,包括对各种字符集的支持,日期和时间的表示,数值和货币的处理等等。毕竟,在中国和在美国,人们表示日期的习惯是不同的。 

  容器(containers)部分,STL的一个重要组成部分,涵盖了许多数据结构,比如前面曾经提到的链表,还有:vector(类似于大小可动态增加的数组)、queue(队列)、stack(堆栈)……。string也可以看作是一个容器,适用于容器的方法同样也适用于string。现在你可以轻松的完成数据结构课程的家庭作业了。

  算法(algorithms)部分,STL的一个重要组成部分,包含了大约70个通用算法,用于操控各种容器,同时也可以操控内建数组。比如:find用于在容器中查找等于某个特定值的元素,for_each用于将某个函数应用到容器中的各个元素上,sort用于对容器中的元素排序。所有这些操作都是在保证执行效率的前提下进行的,所以,如果在你使用了这些算法之后程序变得效率底下,首先一定不要怀疑这些算法本身,仔细检查一下程序的其他地方。 

  迭代器(iterators)部分,STL的一个重要组成部分,如果没有迭代器的撮合,容器和算法便无法结合的如此完美。事实上,每个容器都有自己的迭代器,只有容器自己才知道如何访问自己的元素。它有点像指针,算法通过迭代器来定位和操控容器中的元素。 

  数值(numerics)部分,包含了一些数学运算功能,提供了复数运算的支持。 

  输入/输出(input/output)部分,就是经过模板化了的原有标准库中的iostream部分,它提供了对C++程序输入输出的基本支持。在功能上保持了与原有iostream的兼容,并且增加了异常处理的机制,并支持国际化(internationalization)。 

  总体上,在C++标准函数库中,STL主要包含了容器、算法、迭代器。string也可以算做是STL的一部分。 

  正如前面所提到的,在STL的背后蕴含着泛型化程序设计(GP)的思想,在这种思想里,大部分基本算法被抽象,被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各种不同情形。这一思想和面向对象的程序设计思想(OOP)不尽相同,因为,在OOP中更注重的是对数据的抽象,即所谓抽象数据类型(Abstract Data Type),而算法则通常被附属于数据类型之中。几乎所有的事情都可以被看作类或者对象(即类的实例),通常,我们所看到的算法被作为成员函数(member function)包含在类(class)中,类和类则构成了错综复杂的继承体系。 

  尽管在象C++这样的程序设计语言中,你还可以用全局函数来表示算法,但是在类似于Java这样的纯面向对象的语言中,全局函数已经被"勒令禁止"了。因此,用Java来模拟GP思想是颇为困难的。如果你对前述的STL历史还有印象的话,应该记得Alexander Stepanove也曾用基于OOP的语言尝试过实现GP思想,但是效果并不好,包括没有引入模板之前的C++语言。站在巨人的肩膀上,我们可以得出这样的结论,在OOP中所体现的思想与GP的思想确实是相异的。C++并不是一种纯面向对象的程序设计语言,它的绝妙之处,就在于既满足了OOP,又成全了GP。对于后者,模板立下了汗马功劳。另外,需要指出的是,尽管GP和OOP有诸多不同,但这种不同还不至于到"水火不容"的地步。并且,在实际运用的时候,两者的结合使用往往可以使问题的解决更为有效。作为GP思想实例的STL本身便是一个很好的范例,如果没有继承,不知道STL会是什么样子,似乎没有人做过这样的试验。
  相信你对STL的感性认识应该有所提高了,是该做一些实际的工作了,那么我们首先来了解一下STL的不同实现版本。ANSI/ISO C++文件中的STL是一个仅被描述在纸上的标准,对于诸多C++编译器而言,需要有各自实际的STL,它们或多或少的实现了标准中所描述的内容,这样才能够为我们所用。之所以有不同的实现版本,则存在诸多原因,有历史的原因,也有各自编译器生产厂商的原因。以下是几个常见的STL实现版本。 

  HP STL是所有其它STL实现版本的根源。它是STL之父Alexander Stepanov在惠普的Palo Alto实验室工作时,和Meng Lee共同完成的,是第一个STL的实现版本(参见1.2节)。这个STL是开放源码的,所以它允许任何人免费使用、复制、修改、发布和销售该软件和相关文档,前提是必须在所有相关文件中加入HP STL的版本信息和授权信息。现在已经很少直接使用这个版本的STL了。 

  P. J. Plauger STL属于个人作品,由P. J. Plauger本人实现,是HP STL的一个继承版本,因此在其所有头文件中都含有HP STL的相关声明,同时还有P. J. Plauger本人的版权声明。P. J. Plauger是标准C中stdio库的早期实现者,现在是C/C++ User's Journal的主编,与Microsoft保持着良好的关系。P. J. Plauger STL便是被用于Microsoft的Visual C++中的。在Windows平台下的同类版本中,其性能不错,但是queue组件(队列,一种容器)的效率不理想,同时由于Visual C++对C++语言标准的支持不是很好(至少直到VC6.0为止,还是如此),因此一定程度上影响了P. J. Plauger STL的性能。此外,该版本的源代码可读性较差,你可以在VC的Include子目录下找到所有源文件(比如:C:\Program Files\Microsoft Visual Studio\VC98\Include)。因为不是开放源码的(open source),所以这些源代码是不能修改和销售的,目前P.J. Plauger STL由Dinkumware公司提供相关服务. 

  Rouge Wave STL是由Rouge Wave公司实现的,也是HP STL的一个继承版本,除了HP STL的相关声明之外,还有Rouge Wave公司的版权声明。同时,它也不是开放源码的,因此无法修改和销售。该版本被Borland C++ Builder所采用,你可以在C++ Builder的Include子目录下找到所有头文件(比如:C:\Program Files\Borland\Cbuilder5\Include)。尽管Rouge Wave STL的性能不是很好,但由于C++ Builder对C++语言标准的支持还算不错,使其表现在一定程度上得以改善。此外,其源代码的可读性较好。可以从如下网站得到更详细的情况介绍: 

  STLport最初源于俄国人Boris Fomitchev的一个开发项目,主要用于将SGI STL的基本代码移植到其他诸如C++Builder或者是Visual C++这样的主流编译器上。因为SGI STL属于开放源码,所以STLport才有权这样做。目前STLport的最新版本是4.5。可以从如下网站得到更详细的情况介绍: 

  SGI STL是由Silicon Graphics Computer System, Inc公司实现的,其设计者和编写者包括Alexander Stepanov和Matt Austern,同样它也是HP STL的一个继承版本。它属于开放源码,因此你可以修改和销售它。SGI STL被GCC(linux下的C++编译器)所采用,你可以在GCC的Include子目录下找到所有头文件(比如:C:\cygnus\cygwin-b20\include\g++\include)。由于GCC对C++语言标准的支持很好,SGI STL在linux平台上的性能相当出色。此外,其源代码的可读性也很好。



posted @ 2010-06-02 00:17 幽梦新影 阅读(442) | 评论 (0)编辑 收藏

C++类库:OTL通用的数据库连接类库

OTL是一个纯C++的通用数据库连接模板库,可以支持各种当下流行的数据库,如Oracle,Sybase, MySQL, PostgreSQL, EnterpriseDB, SQLite,  MS ACCESS, Firebird等等.它是一个跨平台类库,在MS Windows, Linux/Unix/Mac OS X 都可以使用。

下载网址:http://otl.sourceforge.net/

OTL使用简单, 只要头文件中包含有: #include "otlv4.h" 就可,实际上整个OTL就一个.H的文件,使用起来极为的方便。

OTL使用方法:

1、首先指定要连接的数据库类型,OTL用宏定义来指定要连接的数据库类型。OTL会根据这个宏定义来初始化数据库连接的环境。

相关的宏定义列表 http://otl.sourceforge.net/otl3_compile.htm

如: #define OTL_ORA8I 表示连接Oracle 8i 数据库。

 

2、例子

#include <iostream>
using namespace std;
#include <stdio.h>

#define OTL_ORA8I // 指定连接的数据库类型
#include <otlv4.h> // include the OTL 4 header file

otl_connect db; // 定义数据库实例

 

void insert()
// 添加记录

{
 otl_stream o(50, // buffer size
              "insert into test_tab values(:f1<float>,:f2<char[31]>)",
                 // SQL statement
              db // connect object
             );
 char tmp[32];

 for(int i=1;i<=100;++i){
#if defined(_MSC_VER)
#if (_MSC_VER >= 1400) // VC++ 8.0 or higher
  sprintf_s(tmp,sizeof(tmp),"Name%d",i);
#else
  sprintf(tmp,"Name%d",i);
#endif
#else
  sprintf(tmp,"Name%d",i);
#endif
  o<<static_cast<float>(i)<<tmp;
 }
}

//查询记录

void select()
{
 otl_stream i(50, // buffer size
              "begin "
               open :cur1 for "
                select * from test_tab "
                where f1>=:f<int> and f1<=:f*2; "
              "end;", // SELECT statement via referenced cursor
              db, // connect object
              ":cur1" // referenced cursor placeholder name
             );
   // create select stream
 
 otl_column_desc* desc;
 int desc_len;

 i<<4; // Before the child SELECT statement can be described,
       // the PL/SQL master block needs to be executed.
       // Forcing the execution of the blcok by entering its input
       // patameter.

 desc=i.describe_select(desc_len);

 for(int n=0;n<desc_len;++n){
  cout<<"========== COLUMN #"<<n+1<<" ==========="<<endl;
  cout<<"name="<<desc[n].name<<endl;
  cout<<"dbtype="<<desc[n].dbtype<<endl;
  cout<<"otl_var_dbtype="<<desc[n].otl_var_dbtype<<endl;
  cout<<"dbsize="<<desc[n].dbsize<<endl;
  cout<<"scale="<<desc[n].scale<<endl;
  cout<<"prec="<<desc[n].prec<<endl;
  cout<<"nullok="<<desc[n].nullok<<endl;
 }
 

}

int main()
{
 otl_connect::otl_initialize(); // 初始化Oracle环境
 try{

  db.rlogon("scott/tiger"); // 连接Oracle

  otl_cursor::direct_exec
   (
    db,
    "drop table test_tab",
    otl_exception::disabled // disable OTL exceptions
   ); // drop table

  otl_cursor::direct_exec
   (
    db,
    "create table test_tab(f1 number, f2 varchar2(30))"
    );  // create table

  insert(); 
  select();

 }

 catch(otl_exception& p){ // intercept OTL exceptions
  cerr<<p.msg<<endl; // print out error message
  cerr<<p.stm_text<<endl; // print out SQL that caused the error
  cerr<<p.var_info<<endl; // print out the variable that caused the error
 }

 db.logoff(); //断开数据库连接

 return 0;

}

posted @ 2010-06-02 00:05 幽梦新影 阅读(6181) | 评论 (1)编辑 收藏

2010年6月1日 #

boost库linux编译安装

    相对于Windows来,Linux下的boost编译简单至极。没有那么多的可选编译器,没有那长的编译时间,没有那么多的硬盘使用量,统一的inlude和lib目录,你熟悉命令行,不使用IDE,不需要我那么罗嗦的介绍怎么配置EditPlus。

首先是下载boost,可以在此
http://sourceforge.net/projects/boost
寻找一个合适的版本。比如我下载的是boost_1_33_1.tar.gz,解压到/opt。

tar xzvf boost_1_33_1.tar.gz -C/opt

提醒:做这些事情的时候你需要有root权限。

进入boost目录:

cd /opt/boost_1_33_1

首先我们要编译bjam:

cd tools/build/jam_src/
./build.sh

很快编译结束,默认情况下,bjam会被复制到/usr/local/bin/bjam。

现在你可以使用bjam编译boost了。

cd ../../..
bjam -sTOOLS=gcc install

编译时间不会如windows那么长久,在我的电脑上编译了大约40分钟。你可以在前后使用df命令检查下磁盘使用,在我的电脑上,编译boost花费了500M的空间。

使用install会把头文件复制到/usr/local/include/boost-1_33_1中,把生成的lib复制到/usr/local/lib中。这些完成之后,记得要使用ldconfig来更新动态链接库。

在测试两个例子之前,我们先设置几个环境变量。

BOOST_ROOT=/opt/boost_1_33_1
BOOST_INCLUDE=/usr/local/include/boost-1_33_1
BOOST_LIB=/usr/local/lib

为了使其能够在登录时自动导入,你可以写一个脚本:
#!/bin/sh
#boost settings
BOOST_ROOT=/opt/boost_1_33_1
BOOST_INCLUDE=/usr/local/include/boost-1_33_1
BOOST_LIB=/usr/local/lib
export BOOST_ROOT BOOST_INCLUDE BOOST_LIB

将其保存为/etc/profile.d/boost.sh,并使用chmod a+x boost.sh设置执行权限。

现在我们可以写两段代码来测试了。

第一个测试文件是lex.cpp:

#include <boost/lexical_cast.hpp>
#include <iostream>

int main()
{
using boost::lexical_cast;
int a = lexical_cast<int>("123");
double b = lexical_cast<double>("123.12");
std::cout<<a<<std::endl;
std::cout<<b<<std::endl;
return 0;
}

编译:
g++ lex.cpp -I$BOOST_ROOT -o lex

运行:
./lex

输出:
123
123.12

你可以将$BOOST_ROOT改为$BOOST_INCLUDE,如果你没有设置环境变量,可以改为/opt/boost_1_33_1或者/usr/local/include/boost-1_33_1。

我们的第二个例子是re.cpp:

#include <iostream>
#include <string>
#include <boost/regex.hpp>

int main() {

std::string s = "who,lives:in-a,pineapple under the sea?";

boost::regex re(",|:|-|\\s+");
boost::sregex_token_iterator
p(s.begin( ), s.end( ), re, -1);
boost::sregex_token_iterator end;

while (p != end)
std::cout << *p++ << '\n';
}

编译:
g++ re.cpp -I$BOOST_ROOT -lboost_regex-gcc -o re

运行:
./re

输出:
who
lives
in
a
pineapple
under
the
sea?

这里要使用-l指定了链接库。

现在boost的基本安装配置已经完成,但是我们可以再改进下。

如果不想每次都指定boost头文件目录,可以将其link到/usr/include中:

ln -s /opt/boost_1_33_1/boost /usr/include/boost

或者:

ln -s /usr/local/include/boost-1_33_1/boost /usr/include/boost

如果你依然嫌boost编译后占用的空间太大,可以在boost目录下使用bjam clean:
cd /opt/boost_1_33_1
bjam -sTOOLS=gcc clean

这个命令会清除编译时的中间文件,/usr/local/lib下带版本号的boost libs,和/usr/local/include下的boost头文件。但是同时节省了几百M的硬盘空间。

所以如果你使用了clean,记得将BOOST_INCLUDE更为BOOST_ROOT(/opt/boost_1_33_1),将 /usr/include/boost link到/opt/boost_1_33_1/boost,再有就是编译链接时的boost lib不要带版本号。

如果你觉得编译时手动链接敲那么长的名字比较麻烦,可以使用脚本来自动寻找链接:

#!/usr/bin/python

import os
import sys
import re

BOOST_ROOT = os.getenv('BOOST_ROOT')
BOOST_LIB = os.getenv('BOOST_LIB')
#BOOST_ROOT = '/opt/boost_1_33_1'
#BOOST_LIB = '/usr/local/lib'

def getlibs():
alls = os.listdir(BOOST_LIB)
libpattern = re.compile(r'^libboost_([^-]+)-gcc')
libs = {}
for lib in alls:
m = libpattern.match(lib)
if m:
libs[m.group(1).lower()] = 1
return libs


pattern = re.compile(r'^\s*#include\s*<\s*boost/(.+)\.(h|hpp)\s*>')
libs = getlibs()
libskeys = libs.keys()
includes = {}

ENV = os.environ


ARGV = sys.argv[1:]
files = ARGV
if len(files) == 0:
sys.exit()

for f in files:
if f.lower().endswith('.cpp'):
fp = open(f, 'r')
lines = fp.readlines()
for ln in lines:
m = pattern.match(ln)
if m:
libname = m.group(1).lower()
if libname in libskeys:
includes[libname] = 1

libline = ' '.join(map(lambda lib: '-lboost_'+lib+'-gcc', includes.keys()))


obj = ARGV[0]
obj = obj[:len(obj)-4]

#cmd = 'g++ %s -I%s %s -o %s' % (' '.join(files), BOOST_ROOT, libline, obj)
cmd = 'g++ %s %s -o %s' % (' '.join(files), libline, obj)

print cmd
os.system(cmd)

将这段代码写进/usr/local/bin/gccboost,赋予执行权限。

使用方法:
gccboost lex.cpp
gccboost re.cpp

注意:使用此命令假设boost头文件在/usr/include中,如果假设不成立,请自行修改脚本此行:
cmd = 'g++ %s %s -o %s' % (' '.join(files), libline, obj)

为之前的注释行:
cmd = 'g++ %s -I%s %s -o %s' % (' '.join(files), BOOST_ROOT, libline, obj)

如若BOOST_ROOT和BOOST_LIB环境变量不存在,修改下面两行代码:
BOOST_ROOT = os.getenv('BOOST_ROOT')
BOOST_LIB = os.getenv('BOOST_LIB')

为之后注释行:
BOOST_ROOT = '/opt/boost_1_33_1'
BOOST_LIB = '/usr/local/lib'

另外,gccboost将会自动修改输出的文件名为*.cpp的文件名(如lex.cpp将输出lex),如果不需要,请将下面的代码:
cmd = 'g++ %s %s -o %s' % (' '.join(files), libline, obj)

改为:
cmd = 'g++ %s %s' % (' '.join(files), libline)


Boost安装历程至此基本结束。

posted @ 2010-06-01 23:36 幽梦新影 阅读(7475) | 评论 (0)编辑 收藏

在Linux系统中安装和配置ACE(转)

本文详细描述了在Linux操作系统上安装和配置“自适应通信环境(ACE)”的过程和注意事项。
文中的描述基于RedHat Linux 9操作系统和ACE 5.4版

 

准备工作:

 

1.确保你的Linux操作系统的开发环境(gcc、make……)是完整且可用的。
2.在安装ACE的过程中,可能需要root权限,因此确保你拥有root帐户的密码。
3.对于典型的Redhat9系统,autoconf程序的版本可能过低,你需要首先升级它。

 

   升级的步骤如下:

 

1.在控制台中输入 autoconf -V,查看你的autoconf程序的版本
2.如果低于2.57g,你需要到http://www.gnu.org/software/autoconf/去下载最新版本的autoconf程序,目前autoconf程序的版本是2.59
3.根据tarball中的安装说明,编译并安装升级autoconf程序
开始安装:

 

经过上面的准备工作,现在你已经具备了安装ACE的条件。下面开始正式的安装工作。

 

1.首先确定ACE的安装路径,并建立相应的目录。
这里,我们把ACE安装在/home/zhc/ace/的目录下,先执行
mkdir /home/zhc/ace
2.然后将获得的ACE源代码包解至该目录下。
tar zxvf ACE-5.4.tar.gz /home/zhc/ace
3.这时,在ace的目录下会建立一个名为ACE_wrappers的子目录,ACE所有的源代码、工具、和例子都在这个目录中。
先进入该目录,执行
cd /home/zhc/ace/ACE_wrappers
然后建立一个子目录,用于存放ACE编译后的目标文件
mkdir build
cd build
4.接着,执行configure脚本,检查你的系统环境,配置并生成适合你的系统的Makefile文件。
在执行configure脚本时,可以加入许多配置选项,其详细说明可以参看ACE_wrappers目录下的ACE-INSTALL.html文件,
对于Redhat9系统来说,不必加任何参数,ACE就可以很好的工作了。
../configure
5.在漫长的检查和配置之后,如果没有什么问题,你就可以开始编译了(如果要让ace支持ICMP 和对c++库的支持,需要在config.h头文件中加上#define ACE_HAS_STANDARD_CPP_LIBRARY 1 和#define ACE_HAS_ICMP_SUPPORT 1)。
这一步很简单,执行
make
然后,泡一杯茶,静静的等待就行了。
6.如果编译顺利的通过(通常都会是这样的),那么恭喜你,你已经成功了一大半了,下面要做的仅仅是以些配置工作而已。
接下来的工作是安装,这一步是可选的,目的是把编译生成的ACE的库文件、头文件和手册页等安装到/usr/local的相应目录中去,为了今后使用的方便,我建议你还是进行这一步,执行
su
root's password
make install
7.安装之后,我们就可以进行最后的配置工作了。
首先设置环境变量ACE_ROOT,执行
setenv ACE_ROOT /home/zhc/ace/ACE_wrappers
注意其中的路径要根据你的实际情况而定
如果你不想每次都手工设定路径,可以编辑你的bash的配置文件,执行
cd
vi .bash_profile
在其中填加如下两行
ACE_ROOT=/home/work/research/ace/ACE_wrappers
export ACE_ROOT
8.然后,在$ACE_ROOT/ace目录中创建一个名为config.h的文件,在其中包含如下一行
#include "ace/config-linux.h"
或者,简单起见,你也可以直接建立一个指向config-linux.h的符号链接,执行
ln -s config-linux.h config.h
9.同样,在$ACE_ROOT/include/makeinclude目录中创建一个名为platform_macros.GNU的文件,在其中包含如下一行
include $(ACE_ROOT)/include/makeinclude/platform_linux.GNU
或者,简单起见,你也可以直接建立一个指向platform_linux.GNU的符号链接,执行
ln -s platform_linux.GNU platform_macros.GNU
10.最后一步,设置环境变量LD_LIBRARY_PATH,执行
setenv LD_LIBRARY_PATH $ACE_ROOT/ace:$ACE_ROOT/lib:
/usr/local/lib:$LD_LIBRARY_PATH
或者在~/.bash_profile文件中添加如下两行
LD_LIBRARY_PATH=$ACE_ROOT/ace:$ACE_ROOT/lib:
/usr/local/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
安装完成:

 

经过上面的步骤,ACE已经安装到了您的系统上了,下面我们将编译并执行ACE的例程以验证我们的工作。
这里我们以《C++网络编程,卷一》所带的例子为例。

 

1:进入例程目录,执行
cd $(ACE_ROOT)/examples/C++NPv1
2:编译例子程序,执行
make
如果前面的安装和配置正确,很快就能够得到编译后的例子程序。
3:分别执行一个服务器程序(随便哪一个都行)和一个客户端程序(Logging_Client),如果程序运行正确,说明前面的安装和配置成功,下面你就可以开始你的ACE学习之旅了

posted @ 2010-06-01 23:31 幽梦新影 阅读(423) | 评论 (0)编辑 收藏

2009年8月28日 #

开始C++的历程

今天正式开始~~

posted @ 2009-08-28 21:25 幽梦新影 阅读(211) | 评论 (0)编辑 收藏

仅列出标题