获取 delete[]中的数组大小

看一个小例子:

#include <iostream>

using namespace std;

class A {
public:
    A() { cout << "A::A()" << endl; }
    ~A() { cout << "A::~A()" << endl; }
};

int main() {
    A* a = new A[5];
    delete[] a;

    return 0;
}

编译执行输出:

A::A()
A::A()
A::A()
A::A()
A::A()
A::~A()
A::~A()
A::~A()
A::~A()
A::~A()

上面的输出显示程序正确释放了5个A对象。 现在的问题是:我们在delete[] a语句中并没有给出对象数组的大小,那么系统是如何做到正确释放对象个数的呢?

接着看下面的程序段:

#include <iostream>

using namespace std;

class A {
public:
    A() { cout << "A::A()" << endl; }
    ~A() { cout << "A::~A()" << endl; }
};

int main() {
    A* a = new A[5];

    int addr = (int)a - 4;
    cout << "delete[] size = " << *(int*)addr << endl;

    delete[] a;

    return 0;
}

编译执行:

A::A()
A::A()
A::A()
A::A()
A::A()
delete[] size = 5
A::~A()
A::~A()
A::~A()
A::~A()
A::~A()

结论: 系统在new一个数组对象的时候会把数组大小存放在返回的内存地址的前4个字节中

linux C 获取线程号

#include <iostream>
#include <sys/types.h>
#include <pthread.h>
#include <sys/syscall.h>

using namespace std;

pid_t gettid() {

    return syscall(SYS_gettid);
}

int main() {

    pid_t t;
    t = gettid();
    cout << "pid_t = " << t << endl;
    return 0;
}

/proc/pid/status各项定义

Name: gedit /*进程的程序名*/
State: S (sleeping) /*进程的状态信息*/
Tgid: 9744 /*线程组号*/
Pid: 9744 /*进程pid*/
PPid: 7672 /*父进程的pid*/
TracerPid: 0 /*跟踪进程的pid*/
Uid: 1000    1000    1000    1000 /*uid euid suid fsuid*/
Gid: 1000    1000    1000    1000 /*gid egid sgid fsgid*/
FDSize: 256 /*文件描述符的最大个数,file->fds*/
Groups: 0 4 20 24 25 29 30 44 46 107 109 115 124 1000 /*启动该进程的用户所属的组的id*/
VmPeak: 60184 kB /*进程地址空间的大小*/
VmSize: 60180 kB /*进程虚拟地址空间的大小reserved_vm:进程在预留或特殊的内存间的物理页*/
VmLck: 0 kB /*进程已经锁住的物理内存的大小.锁住的物理内存不能交换到硬盘*/
VmHWM: 18020 kB /*文件内存映射和匿名内存映射的大小*/
VmRSS: 18020 kB /*应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)*/
VmData: 12240 kB /*程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据*/
VmStk: 84 kB /*进程在用户态的栈的大小*/
VmExe: 576 kB /*程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 */
VmLib: 21072 kB /*被映像到任务的虚拟内存空间的库的大小*/
VmPTE: 56 kB /*该进程的所有页表的大小*/
Threads: 1 /*共享使用该信号描述符的任务的个数*/
SigQ: 0/8183 /*待处理信号的个数/目前最大可以处理的信号的个数*/
SigPnd: 0000000000000000 /*屏蔽位,存储了该线程的待处理信号*/
ShdPnd: 0000000000000000 /*屏蔽位,存储了该线程组的待处理信号*/
SigBlk: 0000000000000000 /*存放被阻塞的信号*/
SigIgn: 0000000000001000 /*存放被忽略的信号*/
SigCgt: 0000000180000000 /*存放被俘获到的信号*/
CapInh: 0000000000000000 /*能被当前进程执行的程序的继承的能力*/
CapPrm: 0000000000000000 /*进程能够使用的能力,可以包含CapEff中没有的能力,这些能力是被进程自己临时放弃的*/
CapEff: 0000000000000000 /*是CapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性*/
Cpus_allowed: 01 /*可以执行该进程的CPU掩码集*/
Mems_allowed: 1 
voluntary_ctxt_switches: 1241 /*进程主动切换的次数*/
nonvoluntary_ctxt_switches: 717 /*进程被动切换的次数*/

使用udev规则固定设备名

OS:ubuntu 12.04LTE

查询设备信息

udevadm info --attribute-walk --name=/dev/video0

其中/dev/video0是一个usb的摄像头。当有其他视频设备插入机器的时候,就不能够保证这个摄像头的设备文件还是/dev/video0了,可能是/dev/video1等等,这样就无法唯一标识这个设备,将不利于自动化脚本处理。 下面通过编写自己的udev 规则来固定这个设备的设备名称。

输出(节选):

 looking at device '/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/video4linux/video0':
    KERNEL=="video0"
    SUBSYSTEM=="video4linux"
    DRIVER==""
    ATTR{name}=="A4 TECH HD PC Camera"
    ATTR{index}=="0"

上面的输出可以确定该设备的系统设备名为 A4 TECH HD PC Camera

编写udev规则

ubuntu下udev rules文件在/etc/udev/rules.d/下,在该目录下建立文件: 60-usb_camera.rules,文件内容如下:

SUBSYSTEM=="video4linux",ATTRS{name}=="A4 TECH HD PC Camera",SYMLINK+="usb_camera"

这条语句告知udev,当发现插入设备的SUBSYSTEM为video4linux,并且设备的name属性是A4 TECH HD PC Camera,那么建立一个软链接到这个设备的设备文件。 usb_camera就是我们需要的固定设备名称。我在这里只是简单匹配了name这个属性,可能不适合其他复杂的环境。 键值对的名称一定要严格匹配,”[“,”]”需要转义。

重启udev

重启udev服务使新的规则生效:

/etc/init.d/udev restart

测试新规则

重新插入usb摄像头,在/dev/目录下可以发现设备usb_camera。在自动化脚本中,我们可以直接使用/dev/usb_camera

更多参考

关于udev规则编写的更多细节,可以查看 这里

CPP 单例模式和缺陷

实现一个单例模式

class Singleton {
    private:
        Singleton() { cout << "Singleton::constructor" << endl; }
        ~Singlton() { cout << "Singleton::destructor" << endl; }
        Singleton(const Singleton&) {};
        Singleton &operator=(const Singleton&) {};
    public:
        static Singleton* getInstance() {
            if(m_aInstance == NULL) {
                m_aInstance = new Singleton();
            }
            return m_aInstance;
        }
        void show() {
            cout << "Singleton::show" << endl;
        }
    private:
        static Singleton* m_aInstance;
};

Singleton* Singleton::m_aInstance = NULL;

int main(int argc, char **argv) {
    Singleton* aSingleton = Singleton::getInstance();
    aSingleton->show(); 
    return 0;
}
Singleton::constructor
Singleton::show

系统会自动调用在栈和静态数据区上分配的对象的析构函数来释放资源。

修改程序如下:

class Singleton {
    private:
        Singleton() { cout << "Singleton::constructor" << endl; }
        ~Singleton() { cout << "Singleton::destructor" << endl; }
        Singleton(const Singleton&) {};
        Singleton &operator=(const Singleton&) {};
    public:
        static Singleton* getInstance() {
            if(m_aInstance == NULL) {
                m_aInstance = new Singleton();
            }
            return m_aInstance;
        }
        void show() {
            cout << "Singleton::show" << endl;
        }

    private:
        class Garbage{
            public:
                ~Garbage() {
                    if(m_aInstance != NULL) {
                        delete m_aInstance;
                    }
                }
        };
    
    private:
        static Singleton* m_aInstance;
        static Garbage m_garbage;
};

Singleton* Singleton::m_aInstance = NULL;
Singleton::Garbage Singleton::m_garbage;

int main(int argc, char **argv) {
    Singleton* aSingleton = Singleton::getInstance();
    aSingleton->show(); 
    return 0;
}
Singleton::constructor
Singleton::show
Singleton::destructor

我们看到Singleton::destructor被明确的执行了。