C++ Tips

  1. 自定义class,存在析构函数,那么需要同时定义或者删除拷贝构造函数和拷贝赋值函数。原因是,在拷贝构造或者拷贝复制的过程中,为浅拷贝,当程序结束,析构函数介入时,可能存在析构两次的情况。
  1. 右值,int &&可以自动转换为int const &。

  2. __restrict关键字,告诉编译器,指针不存在重叠的情况,编译器可以进行优化,所有的非const指针都可以加上__restrict关键字,如:int * __restrict a。对于vector容器,__restrict关键字不生效,可以尝试#pragma omp simd或者#pragma GCC ivdep

  3. 关于malloc和new

    1
    2
    3
    int *a = new int[102400];

    int *a = (int *)malloc(102400 * sizeof(int));

    以上申请内存的两种语句,在实际生产环境,执行时并不会真正的分配内存,而是将这一段内存标记为不可用,即:invalid。待需要用到a数组:赋值或者其他操作时,会触发缺页中断,page fault。此时进入内核,查询此段内存是否之前malloc过,如果查询到,那么内存标记为可用,此时程序正常运行,如果未查询到malloc记录,那么触发段错误,segmentation fault。

    以上两种申请内存的语句,不会进行置零操作,初始化数组时,内存被写入,此时操作系统才进行实际的内存分配,因此测试两次内存赋值操作会发现时间不同。对于new操作符有一个简便方法

    1
    int *a = new int[102400]{};

    常见的自定义String类中,无参数构造函数也可以进行以下简单的定义:注意new char[1]后面的一对大括号

    1
    String::String() : m_length{0}, m_string{new char[1]{}}{}

  4. 原子操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    type __sync_fetch_and_add (type *ptr, type value, ...) // 将value加到*ptr上,结果更新到*ptr,并返回操作之前*ptr的值
    type __sync_fetch_and_sub (type *ptr, type value, ...) // 从*ptr减去value,结果更新到*ptr,并返回操作之前*ptr的值
    type __sync_fetch_and_or (type *ptr, type value, ...) // 将*ptr与value相或,结果更新到*ptr, 并返回操作之前*ptr的值
    type __sync_fetch_and_and (type *ptr, type value, ...) // 将*ptr与value相与,结果更新到*ptr,并返回操作之前*ptr的值
    type __sync_fetch_and_xor (type *ptr, type value, ...) // 将*ptr与value异或,结果更新到*ptr,并返回操作之前*ptr的值
    type __sync_fetch_and_nand (type *ptr, type value, ...) // 将*ptr取反后,与value相与,结果更新到*ptr,并返回操作之前*ptr的值
    type __sync_add_and_fetch (type *ptr, type value, ...) // 将value加到*ptr上,结果更新到*ptr,并返回操作之后新*ptr的值
    type __sync_sub_and_fetch (type *ptr, type value, ...) // 从*ptr减去value,结果更新到*ptr,并返回操作之后新*ptr的值
    type __sync_or_and_fetch (type *ptr, type value, ...) // 将*ptr与value相或, 结果更新到*ptr,并返回操作之后新*ptr的值
    type __sync_and_and_fetch (type *ptr, type value, ...) // 将*ptr与value相与,结果更新到*ptr,并返回操作之后新*ptr的值
    type __sync_xor_and_fetch (type *ptr, type value, ...) // 将*ptr与value异或,结果更新到*ptr,并返回操作之后新*ptr的值
    type __sync_nand_and_fetch (type *ptr, type value, ...) // 将*ptr取反后,与value相与,结果更新到*ptr,并返回操作之后新*ptr的值
    bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...) // 比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回true
    type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...) // 比较*ptr与oldval的值,如果两者相等,则将newval更新到*ptr并返回操作之前*ptr的值
    __sync_synchronize (...) // 发出完整内存栅栏,内存屏障
    type __sync_lock_test_and_set (type *ptr, type value, ...) // 将value写入*ptr,对*ptr加锁,并返回操作之前*ptr的值
    void __sync_lock_release (type *ptr, ...) // 将0写入到*ptr,(类似对*ptr解锁)

    c++11中atomic

    1. atomic_flag

    1
    2
    3
    std::atomic_flag LOCK = ATOMIC_FLAG_INIT; // 原子布尔类型
    LOCK.test_and_set(); //被设置,则返回true; 否则,返回false
    LOCK.clear(); // 清除atomic_flag对象

    1. atomic对int, char, bool等数据结构进行原子性封装

    1
    2
    3
    4
    5
    std::atomic<int> counter(2); // 等同于counter.load(2);
    int old = counter.fetch_add(2); // 等同于counter+=2; 注意:counter = counter + 1;并不是原子操作; fetch_add会返回旧值
    counter.load(); // 读取,等同于std::cout << counter << std::endl;
    int old = counter.exchange(3); // 交换并返回旧值,old = 2
    bool equal = counter.compare_exchange_strong(old, new); // equal with old, counter = new, 返回true, 此处的old为引用,不能直接传入右值2