跳转至

源码解读1

继承了两个类,copyable,or nocopyable

nocopyable只需要让其拷贝构造函数和赋值构造函数定义为=delete即可(c++11特性)或者将其定义为private。其默认构造函数和析构函数需要定义为protectd,使得只能为子类使用,但是子类不具有复制行为。

    class noncopyable {
    public:
        noncopyable(const noncopyable&) = delete;
        void operator=(const noncopyable&) = delete;

    protected:
        noncopyable() = default;
        ~noncopyable() = default;
    };

1. TimeStamp

  • PRId64实现int64的跨平台
    int64在32/64不同的系统上,表示不同,linux上定义如下:

        #if     __WORDSIZE == 64    // 64位机器 
        #define __PRI64_PREFIX  "l" 
        #else                       // 32位机器
        #define __PRI64_PREFIX  "ll"
        #endif
        // 因此在64位的机器上是 ld,32位机器上是lld
        #define PRId64      __PRI64_PREFIX "d"
    
    在如下的格式化代码中,通过PRI64实现跨平台
    string Timestamp::toString() const {
        char buf[32] = {0};
        int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond;   // 整数
        int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond;  // 余数
        snprintf(buf, sizeof(buf)-1, "%" PRId64 ".%06" PRId64 "", seconds, microseconds);
        return buf;
    }
    

    2. Atomic

参考atomic.h文件代码

  • gcc的原子操作

    • __sydnc_val_compare_and_swap(type* ptr, type oval, type nval) 原子比较交换操作:*ptr* = *ptr==oval? nval : *ptr。返回的是没有修改过的*ptr
    • __sync_fetch_and_add(type* ptr, type value) 原子增加操作:value + x,并且返回修改之前的value。线程安全的
    • __sync_lock_test_and_set(type* ptr, type value) 原子赋值操作:*ptr=value
    • volatile volatile 关键字是为了确保本指令不会因为编译器的优化而省略,且要求每次直接读值。即:防止编译器对代码进行优化。

当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,而不是使用保存在寄存器中的备份。

  • gcc编译时选项

         Wall           // 大部分警告 
        -Wextra         // 一些额外的警告
        -Werror         // 当出现警告时转为错误,停止编译
        -Wconversion            // 一些可能改变值的隐式转换,给出警告。
        -Wno-unused-parameter   // 函数中出现未使用的参数,不给出警告。
        -Wold-style-cast        // C风格的转换,给出警告
        -Woverloaded-virtual    // 如果函数的声明隐藏住了基类的虚函数,就给出警告。
        -Wpointer-arith     // 对函数指针或者void *类型的指针进行算术操作时给出警告
        -Wshadow            // 当一个局部变量遮盖住了另一个局部变量,或者全局变量时,给出警告。
        -Wwrite-strings     // 规定字符串常量的类型是const char[length],因此,把这样的地址复制给 non-const char *指针将产生警告.这些警告能够帮助你在编译期间发现企图写入字符串常量 的代码
        -march=native       // 指定cpu体系结构为本地平台
    

    3. Execption

  • 打印backtrace信息

        #include <execinfo.h>
    int 
        backtrace(void** buffer, int size);
    
        char**
        backtrace_symbols(void* const *buffer, int size);
    

    • backtrace 栈回溯,保存各个栈帧的地址
      • buffer是个指针数组, void* buffer[size]
      • 返回值nptr是实际buffer的元素个数,元素是当前进程中活跃的函数。
    • backtrace_symbols
      • 作用 将backtrace函数得到的buffer中的元素(元素是地址)翻译成描述这个地址的字符串。这个字符串组成为:函数名 + 函数的偏移地址 + 16进制的实际的地址,比如:exception_test(_start+0x2a) [0x55661933e5fa]
      • 返回值 上面的这个字符串指针数组作为返回值:char* strings[size]size是函数的传入参数,也即backtrace的返回值。
      • 注意点 这个返回的 **char* strings[size]**是这个函数在内部由malloc分配的内存,因此调用者必须手动 free(strings)。但是buffer不应该被释放,因为它不是由malloc分配的。
    • demagle
          char* 
          abi::__cxa_demangle(const char * mangled_name,
                              char       * output_buffer,
                              size_t     * length,
                              int        * status  
                              )      
      
    • mangled_name:是一个以\0结尾的需要被demangle字符串。
    • output_buffer:存储结果。如果*length满足demangled_name的长度,那么 output_buffer malloc 的长度是*length,否则就需要调用remalloc
    • length:传入传出参数,传入的是output_buffer需要分配的大小,如果长度不够,length就该改变。
    • status
      • 0:demangle成功
      • -1:内存分配失败
      • -2:mangled_name无效
      • -3:参数列表其中一个无效
    • 返回值 指向demangled_name,或者nullptr如果返回失败。 调用者需要 free 这个内存。