Sep 4

         简而言之,产生段错误就是访问了错误的内存段,一般是你没有权限,或者根本就不存在对应的物理内存,尤其常见的是访问0地址.一般来说,段错误就是指访问的内存超出了系统所给这个程序的内存空间。

        一般来说,linux下的调试工具有王牌调试工具gdb,内存检查工具valgrind等。另外,在linux下发生段错误是会产生core文件,可以用gdb来分析它,能很快地分析找到引起错误的函数和相应的函数。

1 .设置发生段错误时产生core文件的方法

 最简单的是在在bash的配置文件.bashrc里面加入一行

ulimit -S -c unlimited > /dev/null 2>&1

  然后注销一下就可以在发生段错误时产生core文件。

  1)使用

ulimit -c
  命令可查看core文件的生成开关。若结果为0,则表示关闭了此功能,不会生成core文件。
   2)使用
   
ulimit -c filesize
命令,可以限制core文件的大小(filesize的单位为kbyte)。

ulimit -c unlimited
则表示core文件的大小不受限制。如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文 件的时候,gdb会提示错误。

2.core文件的名称和生成路径
 ----------------------------
core文件生成路径:
输入可执行文件运行命令的同一路径下。
若系统生成的core文件不带其它任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。

1)/proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展 名,生成的core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。
可通过以下命令修改此文件:

echo "1" > /proc/sys/kernel/core_uses_pid

2)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通过以下命令修改此文件:

echo "/corefile/core-%e-%p-%t" > core_pattern

可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳
以下是参数列表:
    %p - insert pid into filename 添加pid
    %u - insert current uid into filename 添加当前uid
    %g - insert current gid into filename 添加当前gid
    %s - insert signal that caused the coredump into the filename 添加导致产生core的信号
    %t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
    %h - insert hostname where the coredump happened into filename 添加主机名
    %e - insert coredumping executable name into filename 添加命令名

3.core文件的查看

core文件要通过gdb查看。

gdb
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".

(gdb)

然后输入

core-file core.*
就可以看到一些段错误的信息了。

Program terminated with signal 11, Segmentation fault.
[New process 6285]
#0  0xb7fa9e7f in ?? ()
然后再输入

bt

就可以出来函数及行数信息了。
#0  0xb7fa9e7f in ?? ()
#1  0xb7fa9efd in ?? ()
#2  0x0809a393 in std::_Rb_tree_const_iterator<std::pair<perception::Vision::FID const, math::TVector<float, 3u> > >::operator-- (this=0xbfecf7e0)
    at /usr/include/c++/4.3/bits/stl_tree.h:272
#3  0x0809a407 in getSecondRefByFirstValue<perception::Vision::FID, math::TVector<float, 3u> > (m=@0x9a32c84, f=perception::Vision::BALL)
    at ../../../src/lib/Template.hpp:92
#4  0x0809a441 in perception::Vision::pos (this=0x9a32c68,
    oid=perception::Vision::BALL) at ../perception/Vision.h:95
#5  0x0808ef9d in core::WorldModel::updateBall (this=0x817aba0)
    at WorldModel.cpp:447
#6  0x08095009 in core::WorldModel::update (this=0x817aba0, p=
        {px = 0xbfecfa5c, pn = {pi_ = 0x9a2ed84}}) at WorldModel.cpp:88
#7  0x08088863 in core::Agent::run (this=0x817a580) at Agent.cpp:101
#8  0x08055159 in main (argc=2, argv=0xbfecfb64) at main.cpp:3

从main函数开始一直向上就可以锁定发生段错误的位置了。解下来就可以解决段错误了。

注意:待调试的可执行文件,在编译的时候需要加-g,core文件才能正常显示出错信息!

           

Apr 2

boost::scoped_ptr虽然简单易用,但它不能共享所有权的特性却大大限制了其使用范围,而boost::shared_ptr可以解决这一局限。顾名思义,boost::shared_ptr是可以共享所有权的智能指针,首先让我们通过一个例子看看它的基本用法:

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

class implementation
{
public:
    ~implementation() { std::cout <<"destroying implementation\n"; }
    void do_something() { std::cout << "did something\n"; }
};

void test()
{
    boost::shared_ptr<implementation> sp1(new implementation());
    std::cout<<"The Sample now has "<<sp1.use_count()<<" references\n";

    boost::shared_ptr<implementation> sp2 = sp1;
    std::cout<<"The Sample now has "<<sp2.use_count()<<" references\n";
    
    sp1.reset();
    std::cout<<"After Reset sp1. The Sample now has "<<sp2.use_count()<<" references\n";

    sp2.reset();
    std::cout<<"After Reset sp2.\n";
}

void main()
{
    test();
}

该程序的输出结果如下:

The Sample now has 1 references
The Sample now has 2 references
After Reset sp1. The Sample now has 1 references
destroying implementation
After Reset sp2.

可以看到,boost::shared_ptr指针sp1和sp2同时拥有了implementation对象的访问权限,且当sp1和sp2都释放对该对象的所有权时,其所管理的的对象的内存才被自动释放。在共享对象的访问权限同时,也实现了其内存的自动管理。

boost::shared_ptr的内存管理机制:

boost::shared_ptr 的管理机制其实并不复杂,就是对所管理的对象进行了引用计数,当新增一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数加 一;减少一个boost::shared_ptr对该对象进行管理时,就将该对象的引用计数减一,如果该对象的引用计数为0的时候,说明没有任何指针对其 管理,才调用delete释放其所占的内存。

上面的那个例子可以的图示如下:

  1. sp1对implementation对象进行管理,其引用计数为1
  2. 增加sp2对implementation对象进行管理,其引用计数增加为2
  3. sp1释放对implementation对象进行管理,其引用计数变为1
  4. sp2释放对implementation对象进行管理,其引用计数变为0,该对象被自动删除

boost::shared_ptr的特点:

和 前面介绍的boost::scoped_ptr相比,boost::shared_ptr可以共享对象的所有权,因此其使用范围基本上没有什么限制(还是 有一些需要遵循的使用规则,下文中介绍),自然也可以使用在stl的容器中。另外它还是线程安全的,这点在多线程程序中也非常重要。

boost::shared_ptr的使用规则:

boost::shared_ptr并不是绝对安全,下面几条规则能使我们更加安全的使用boost::shared_ptr:

  1. 避免对shared_ptr所管理的对象的直接内存管理操作,以免造成该对象的重释放
  2. shared_ptr并不能对循环引用的对象内存自动管理(这点是其它各种引用计数管理内存方式的通病)。
  3. 不要构造一个临时的shared_ptr作为函数的参数。
    如下列代码则可能导致内存泄漏:
    void test()
    {
        foo(boost::shared_ptr<implementation>(new    implementation()),g());
    }
    正确的用法

    void test()
    {
        boost::shared_ptr<implementation> sp    (new implementation());
        foo(sp,g());
    }
Apr 2

 转自:
http://hi.baidu.com/%D4%B6%B9%C5%B5%A5%CE%BB/blog/item/29888288267e5f90a5c27270.html


还有关于cmake实践的资料,网址是http://www.qtchina.net/?q=node/161
这几天研究了一下CMake,因为感觉在之后的开发中,我们终有一天需要这个工具。

CMake

Cmake 不再使你在构建项目时郁闷地想自杀了.   --一位KDE开发者。

1,背景知识:
    cmake 是 kitware 公司以及一些开源开发者在开发几个工具套件(VTK)的过程中衍生品,最终形成体系,成为一个独立的开放源代码项目。项目的诞生时间是 2001 年。其官方网站是 www.cmake.org,可以通过访问官方网站获得更多关于 cmake 的信息。cmake的流行其实要归功于 KDE4 的开发(似乎跟当年的 svn 一样,KDE 将代码仓库从 CVS 迁移到SVN,同时证明了 SVN 管理大型项目的可用性),在 KDE 开发者使用了近 10 年 autotools之后,他们终于决定为 KDE4 选择一个新的工程构建工具,其根本原因用 KDE 开发者的话来说就是:只有少数几个“编译专家”能够掌握 KDE 现在的构建体系(admin/Makefile.common),在经历了 unsermake, scons 以及cmake 的选型和尝试之后,KDE4 决定使用 cmake 作为自己的构建系统。在迁移过程中,进展异常的顺利,并获得了 cmake 开发者的支持。所以,目前的 KDE4 开发版本已经完全使用 cmake 来进行构建。像kdesvn,rosegarden 等项目也开始使用 cmake,这也注定了 cmake 必然会成为一个主流的构建体系。

2,特点
cmake的特点主要有:
1, 开放源代码(BSD许可证)。2, 跨平台。3, 能够管理大型项目。4, 简化编译构件过程和编译过程。5, 高效率。6, 可扩展。

3,安装cmake
在ubuntu下直接 sudo apt-get install cmake,我装的cmake的版本是2.4-patch 6, ubuntu版本7.04

4, 简单使用
建立一个临时目录 mkdir -p cmake/t1 && cd cmake/t1, 在这个文件夹下写一个最简单的程序main.c。
main.c 文件内容:
//main.c
#include <stdio.h>
int main()
{
     printf("Hello World from t1 Main!\n");
     return 0;
}
在它的同级目录下写一个文件,文件名是CMakeLists.txt(注意文件名大小写),CMakeLists.txt的内容是:
PROJECT (HELLO)
SET(SRC_LIST main.c)
MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})
MESSAGE(STATUS "This is SOURCE dir "${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})

CMakeLists.txt,脚本内容如下
        #标识我们项目的名称
         PROJECT(my_project)
         #添加glib的include路径
         INCLUDE_DIRECTORIES(/usr/include/glib)
         #将common目录的所有文件名写到名为common_var的变量中去
       AUX_SOURCE_DIRECTORY(common common_var)
         # 将main.c main.h添加到PROJECT_FILE变量中
         SET(PROJECT_FILE main.c main.h)
         # 将common_var变量和PROJECT_FILE变量的内容放到ALL_FILE变量中去
         SET(ALL_FILE ${PROJECT_FILE} ${common_var})
         #根据ALL_FILE来生成可执行文件bt_server
         add_executable (bt_server ${ALL_FILE})
         #链接动态链接库libglib2.0.so和libpthread.so
         target_link_libraries(bt_server libglib-2.0.so libpthread.so)

        恩,编译脚本就这样写完了,简单吧。
        下面的步骤更简单
        在你的project下面建立一个目录,目录名叫build #随便你写什么名字都好,不过推荐用build,显得正规一些:)

         进入终端,然后敲击命令 cmake..     #千万要记得后面的两个点。这表示CMakeLists.txt文件存放在上级目录下

        如果cmake成功,你会看到build目录下生成一个makefile文件。此时在终端下敲击make.你的工程就会被编译成可执行文件.


4.1, 开始构件
在这个工程下运行cmake . (. 代表本目录)
然后就会生成这个文件的makefile.
之后运行 make,就可以生成hello程序了。

就是这点简单的使用吧,详细使用有兴趣的话自己去网上找资料吧~