【深入理解C++11:C++新特性解析】第6章 提高性能及操作硬件的能力 测试代码整理

目录

6-1.运行时常量性满足不了一些代码对编译时常量性的需求的一个举例

6-2.非类型模板函数的默认模板参数需要的也是编译时常量,g++98不可过,g++11是可以编过的,clang++11说不可通过

6-3.运行时常量性满足不了一些代码对编译时常量性的需求的一个举例

6-4.constexpr不能直接修饰自定义数据类型,需要定义自定义类型的常量构造函数

6-5.自定义的数据类型的成员函数也要具有编译时常量性

6-6.模板函数是否会被实例化成一个能够满足编译时常量的版本是未知的

6-7.利用常量表达式构造Fibonacci数组

6-8.使用模板元编程的方式来实现Fibonacci

6-9.一个变长函数的简单示例

6-10.用变长模板实现简单的tuple

6-11.一个使用非类型模板的例子

6-12.C++11提案中实现的新的printf的例子

6-13.AIX系统下的一个解包的例子

6-14.使用"sizeof..."这个新操作符来计算参数包中的参数个数(有疑问)

6-15.定义使用模板作为变长模板参数包的一个变长模板

6-16.模板参数包不一定非得作为模板的最后一个参数

6-17.变长模板参数和完美转发结合使用的例子

6-18.使用pthread相关变量及函数来实现原子操作

6-19.使用原子变量实现原子操作

6-20.通过atomic_flag的成员test_and_set及clear来实现一个自旋锁达到T1等待T2的目的

6-21.顺序一致性模型是理想的内存模型,现实是骨感的

6-22.用自旋锁来实现我们想要得到的同步效果

6-23.用store函数中用松散的内存模型,这个指令可以任由编译器重排序或者由处理器乱序执行

6-24.用load来加载变量做自旋判断实现我们想要得到的同步效果

6-25.memory_order_release和memory_order_acquire组合可实现一个较好的平衡

6-26.本例中memory_order_consume比memory_order_acquire更slay一些,“先于发生的关系”被弱化

6-27.并不是所有的全局变量,静态变量都适合在多线程的情况下共享

6-28.展示用atexit注册的函数在程序以exit方式退出时都会被调用(调用次序与注册次序相反)

6-29.多线程情况下可以向at_quick_exit注册快速退出的方法


6-1.运行时常量性满足不了一些代码对编译时常量性的需求的一个举例

const int GetConst(){return 1;} 
void ConstLess(int con){
     int arr[GetConst()] = {0};// 无法通过编译
     enum{e1 = GetConst(),e2}; // 无法通过编译
     switch(cond){
         case GetConst():      // 无法通过编译    
             break;
         default:
             break;
     }   
}
/*
   编译选项:g++ 6-1-1.cpp -c
   代码清单: 6-1
   代码功能:运行时常量性满足不了一些代码对编译时常量性的需求的一个举例
*/

6-2.非类型模板函数的默认模板参数需要的也是编译时常量,g++98不可过,g++11是可以编过的,clang++11说不可通过

enum BitSet{
   V0 = 1 << 0;
   V1 = 1 << 1;
   V2 = 1 << 2;
   VMAX = 1 << 3;
};
const BitSet operator|(BitSet x, BitSet y){
    return static_cast<BitSet>(((int)x|y) &(VMAX -1));
}
template <int i = V0 | V1>
     void LikeConst(){}

/*
   编译选项:g++ 6-1-2.cpp -c
   代码清单: 6-2
   代码功能:非类型模板函数的默认模板参数需要的也是编译时常量,g++98不可过,g++11是可以编过的,clang++11说不可通过
*/

6-3.运行时常量性满足不了一些代码对编译时常量性的需求的一个举例

constexpr int f();
int a = f();
const int b = f();
constexpr int c = f();
constexpr int f(){return 1;}
constexpr int d = f();

6-4.constexpr不能直接修饰自定义数据类型,需要定义自定义类型的常量构造函数

struct MyType{
   constexpr MyType(int x):i(x){}
   int i; 
};
constexpr MyType mt = {0};

/*
   编译选项:g++ 6-1-4.cpp -c (pass)
            clang++ 6-1-4.cpp -c -std=c++11 (pass)
   代码清单: 6-4
   代码功能:constexpr不能直接修饰自定义数据类型,需要定义自定义类型的常量构造函数
*/

6-5.自定义的数据类型的成员函数也要具有编译时常量性

#include <iostream>
using namespace std;
struct Date{
    constexpr Date(int y,int m,int d):year(y),month(m),day(d){}
    constexpr int GetYear()   {return year;}
    constexpr int GetMonth()  {return month;}
    constexpr int GetDay()    {return day;}  
    /*
    优化:
    constexpr int GetYear()   const {return year;}
    constexpr int GetMonth()  const {return month;}
    constexpr int GetDay()    const {return day;}  
    */
   private:
    int year;
    int month;
    int day;
};
constexpr Date PRCfound {1949,10,1};
constexpr int foundmonth = PRCfound.GetMonth();
int main(){

    cout << foundmonth << endl;
    return 0;
}

6-6.模板函数是否会被实例化成一个能够满足编译时常量的版本是未知的

struct NotLiteral{
   NotLiteral(){ i = 5}
   int i;
};
NotLiteral nl;
template<typename T> constexpr T ConstExp(T t){
    return t;
}
void g(){
  NotLiteral nl;
  NotLiteral nl1 = ConstExp(nl);
  constexpr NotLiteral nl2 = ConstExp(nl);
  constexpr int a = ConstExp(1);
}
/*
   编译选项:g++ 6-1-6.cpp -c (no pass)
            clang++ 6-1-6.cpp -c -std=c++11 (no pass)
   代码清单: 6-6 
   代码功能:模板函数是否会被实例化成一个能够满足编译时常量的版本是未知的
*/

6-7.利用常量表达式构造Fibonacci数组

#include <iostream>
using namespace std;
constexpr int Fibonacci(int n){
    return (n == 1)? 1:((n == 2)?1:Fibonacci(n-1)+Fibonacci(n-2));
}
int main(){
    int fib[]={
               Fibonacci(11),
               Fibonacci(12),
               Fibonacci(13),
               Fibonacci(14),
               Fibonacci(15),
               Fibonacci(16)
    };
    for(int i : fib) cout << i <<endl;
    return 0;
}

6-8.使用模板元编程的方式来实现Fibonacci

#include <iostream>
using namespace std;
template<long num>
struct Fibonacci{
    static const long val = Fibonacci<num-1>::val + Fibonacci<num-2>::val;
};
template <> struct Fibonacci<2> {static const long val = 1;};
template <> struct Fibonacci<1> {static const long val = 1;};
template <> struct Fibonacci<0> {static const long val = 0;};
int main(){
   int fib[] ={
       Fibonacci<11>::val,
       Fibonacci<12>::val,
       Fibonacci<13>::val,
       Fibonacci<14>::val,
       Fibonacci<15>::val,
       Fibonacci<16>::val
   };  
   for(int i:fib) cout << i << endl;
   return 0;
}
/*
   编译选项:g++ 6-1-8.cpp (pass)
            clang++ 6-1-78cpp -std=c++11 (pass)
   代码清单: 6-8 
   代码功能:使用模板元编程的方式来实现Fibonacci
*/

6-9.一个变长函数的简单示例

#include <stdio.h>
#include <stdarg.h>
double SumOfFloat(int count,...){
    va_list ap;
    double sum = 0;
    va_start(ap,count);
    for( int i = 0;i<count;i++){
        sum += va_arg(ap,double);
    }
    va_end(ap);
    return sum;
}
int main(){
   printf("%f \n",SumOfFloat(3,1.2f,3.4,5.6));// 10.200000
   return 0;
}

/*
   编译选项:gcc 6-2-1.cpp (pass)
   代码清单: 6-9
   代码功能:一个变长函数的简单示例
*/

6-10.用变长模板实现简单的tuple

template<typename... Elements> class tuple;// 变长模板的声明
template<typename Head,typename... Tail>  // 递归的偏特化定义
class tuple<Head,Tail...>:private tuple<Tail...>{
    Head head;
};
template<> class tuple<>{};  // 边界条件

/*
   编译选项:g++ 6-2-2.cpp -c -std=c++11 (pass)
   代码清单: 6-10
   代码功能:用变长模板实现简单的tuple
*/

6-11.一个使用非类型模板的例子

什么是非类型模板

#include <iostream>
using namespace std;
template <long... num> struct Mutiply;
template <long first,long... last>
struct Mutiply<first,last...>{
    static const long val = first * Mutiply<last...>::val;
};
template<>
struct Mutiply<>{
    static const long val = 2;
};
int main(){
    cout << Mutiply<2,3,4,5>::val << endl;
    cout << Mutiply<22,44,66,88,9>::val << endl;
    return 0;
}
/*
   编译选项:g++ 6-2-3.cpp -std=c++11 (pass)
            clang++ 6-2-3.cpp -std=c++11 (pass)
   代码清单: 6-11
   代码功能:一个使用非类型模板的例子(也可以做为模板元编程的例子)
*/

6-12.C++11提案中实现的新的printf的例子

#include <iostream>
#include <stdexcept>
using namespace std;
void Printf(const *s){
    while(*s){
        if(*s == '%' && *++s != '%')
           throw runtime_error("invalid format string:missing argument");
        cout << *s++;
    }
}
template<typename T,typename...Args>
void Printf(const char*s ,T value,Args... args){
    while(*s){
        if(*s == '%' &&*++s !='%'){
            cout << value;
            return Printf(++s,args...);
        }
        cout << *s++;
    }
    throw runtime_error("extra arguments provided to Printf");
}
int main(){
   Printf("hello %s\n",string("world")); 
}

/*
   编译选项:g++ 6-2-4.cpp -std=c++11 (pass)
            clang++ 6-2-4.cpp -std=c++11 (pass)
   代码清单: 6-12
   代码功能:C++11提案中实现的新的printf的例子
*/

6-13.AIX系统下的一个解包的例子

#include <iostream>
using namespace std;
template<typename... T> void DummyWrapper(T... t){}
template<typename... T> T pr(T r){
    cout<< T;
    return t;
}
template<typename... A>
void VTPrint(A... a){
    DummyWrapper(pr(a)...);
};
int main(){
   VTPrint(1,",",1.2,",abc\n");
   return 0;
}
/*
   编译选项:xlC -+ -qlanglvl=variadictemplates 6-2-5.cpp
            g++和clang都无法编译通过,此处我没有实验环境,之后看能不能搭个环境试验下
   代码清单: 6-13
   代码功能:AIX系统下的一个解包的例子
*/

AIX不能在VMware上安装-谢谢哈

6-14.使用"sizeof..."这个新操作符来计算参数包中的参数个数(有疑问)

#include <cassert>
#include <iostream>
using namespace std;
template<class...A> void Print(A...arg){
    assert(false);
/* 非6参数偏特化版本都会默认assert(false),这个是怎么做到的呢?
因为我们仅仅提供了一个特化6参数的版本,其他个数参数的版本都不会被实例化,所以会报错吗?
*/
}
// 特化6参数的版本
void Print(int a1,int a2,int a3,int a4,int a5,int a6){
    cout<< a1 << ","<< a2 << ","<< a3 << ","<< a4 << ","<< a5 << ","<< a6 << endl;
}
template<class... A> int Vaargs(A...args){
    int size = sizeof...(A);
    switch(size){
        case 0:
              Print(99,99,99,99,99,99);
              break;
        case 1:
              Print(99,99,args...,99,99,99);
              break;
        case 2:
              Print(99,99,args...,99,99);
              break;
        case 3:
              Print(args...,99,99,99);
              break;
        case 4:
              Print(99,args...,99);
              break;
        case 5:
              Print(99,args...);
              break;
        case 6:
              Print(args...);
              break;
        default:
              Print(0,0,0,0,0,0);
    }
    return size;
}
int main(void){
     Vaargs();              // 99,99,99,99,99,99
     Vaargs(1);             // 99,99,1,99,99,99
     Vaargs(1,2);           // 99,99,1,2,99,99
     Vaargs(1,2,3);         // 1,2,3,99,99,99
     Vaargs(1,2,3,4);       // 99,1,2,3,4,99
     Vaargs(1,2,3,4,5);     // 99,1,2,3,4,5
     Vaargs(1,2,3,4,5,6);   // 1,2,3,4,5,6
     Vaargs(1,2,3,4,5,6,7); // 0,0,0,0,0,0
     return 0;
}
/*
 编译选项:  g++ 6-2-6.cpp -std=c++11 (pass)
            clang++ 6-2-6.cpp -std=c++11 (pass)
   代码清单: 6-14
   代码功能:使用"sizeof..."这个新操作符来计算参数包中的参数个数(本例有疑惑)
*/

6-15.定义使用模板作为变长模板参数包的一个变长模板

template<typename T,template<typename> class... B> struct Container{};
template<typename T,template<typename> class A,template<typename> class... B> 
struct Container<I,A,B...>{
    A<I> a;
    Container<I,B...> b;
};
template<typename I> struct Container<I>{};

/*
   编译选项:g++ 6-2-7.cpp -std=c++11 -c
   代码清单: 6-15
   代码功能:定义使用模板作为变长模板参数包的一个变长模板
*/

6-16.模板参数包不一定非得作为模板的最后一个参数

#include <cstdio>
#include <tuple>
using namespace std;
template<typename A,typename B> struct S{};
// 两个模板参数包
template< template<typename...> class T,typename... TArgs,template<typename...> class U,typename... UArgs>
struct S<T<TArgs...>,U<UArgs...>>{};
int main(){
   S<int,float> p;
   S<std::tuple<int,char>,std::tuple<float>> s;
   return 0;
}

6-17.变长模板参数和完美转发结合使用的例子

#include <iostream>
using namespace std;
struct A{
   A(){};
   A(const A& a) {cout << "Copy COnstructed"<< __func__ <<endl;}
   A(const A&& a){cout << "Move COnstructed"<< __func__ <<endl;}
};
struct B{
   B(){};
   B(const B& b) {cout << "Copy COnstructed"<< __func__ <<endl;}
   B(const B&& b){cout << "Move COnstructed"<< __func__ <<endl;}
};

template<typename... T> struct MultiTypes;
template<typename T1,typename... T>
struct MultiTypes<T1,T...>:public MultiTypes<T...>{
      T1 t1;
      MultiTypes<T1,T...>(T1 a,T...b):t1(a),MultiTypes<T...>(b...){
          cout << "MultiTypes<T1,T...>(T1 a,T...b)"<<endl;
      }
};
template <> struct MultiTypes<>{
     MultiTypes<>(){ cout << "MultiTypes<>()" << endl;}
};

template <template <typename...>class VariadicType,typename... Args>
VariadicType<Args...> Build(Args&&... args)
{
    return VariadicType<Args...>(std::forward<Args>(args)...);
}
int main(){
    A a;
    B b;
    Build<MultiTypes> (a,b);

}

/*
   编译选项:g++ 6-2-9.cpp -std=c++11 
   代码清单: 6-17
   代码功能:变长模板参数和完美转发结合使用的例子
*/

6-18.使用pthread相关变量及函数来实现原子操作

#include <pthread.h>
#include <iostream>
using namespace std;
static long long total =0 ;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void* fun(void *){
    long long i;
    for(i = 0;i< 100000000LL;i++){// 8个0
        pthread_mutex_lock(&m);
        total += i;
        pthread_mutex_unlock(&m);
    }
}
int main(){
     pthread_t thread1,thread2;
     if(pthread_create(&thread1,NULL,&fun,NULL)){
         throw;
     }
     if(pthread_create(&thread2,NULL,&fun,NULL)){
         throw;
     }
     pthread_join(thread1,NULL);
     pthread_join(thread2,NULL);
     cout << total << endl; // 9999999900000000(8个9,8个0)
     return 0;
}
/*
   编译选项:g++ 6-3-1.cpp -lpthread
   代码清单: 6-18
   代码功能:使用pthread相关变量及函数来实现原子操作

*/

6-19.使用原子变量实现原子操作

#include <atomic>
#include <thread>
#include <iostream>
using namespace std;
atomic_llong total{0};
void func(int){
    for(long long i = 0;i < 100000000LL;++i){
        total += i;
    }
}

int main(){
    thread t1(func,0);
    thread t2(func,0);
    t1.join();
    t2.join();
    cout << total << endl;
    return 0;
}

/*
   编译选项:g++ -std=c++11 6-3-2.cpp -lpthread
   代码清单: 6-19
   代码功能:使用原子变量实现原子操作

*/

6-20.通过atomic_flag的成员test_and_set及clear来实现一个自旋锁达到T1等待T2的目的

#include <thread>
#include <atomic>
#include <iostream>
#include <unistd.h>
using namespace std;
std::atomic_flag lock = ATOMIC_FLAG_INIT;
void f(int n){ 
    while(lock.test_and_set(std::memory_order_acquire))
        cout <<" func-f Waiting from thread" << n << endl;
    cout << "Thread" << n << "starts working" << endl;
}

void g(int n){ 
    cout << "Thread" << n << "is going to start." << endl;
    lock.clear();
    cout << "Thread" << n << "starts working" << endl;
}
int main(){
    lock.test_and_set();
    thread t1(f,1);
    thread t2(g,2);
    t1.join();
    usleep(10);
    t2.join();
    return 0;
}

/*
   编译选项:g++ -std=c++11 6-3-3.cpp -lpthread
   代码清单: 6-20
   代码功能:通过atomic_flag的成员test_and_set及clear来实现一个自旋锁达到T1等待T2的目的
*/

6-21.顺序一致性模型是理想的内存模型,现实是骨感的

#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
atomic<int> a{0};
atomic<int> b{0};
int ValueSet(int){
    int t = 1;
    a = t;
    b = 2;
}
int Observer(int){

    cout << "("<<a << "," << b << "}" << endl;
}
int main(){
   thread t1(ValueSet,0);
   thread t2(Observer,0);
   t1.join();
   t2.join();
   cout << "Got (" << a <<","<< b << ")" << endl;
}

/*
   编译选项:g++ -std=c++11 6-3-4.cpp -lpthread
   代码清单: 6-21
   代码功能:顺序一致性模型是理想的内存模型,现实是骨感的
*/

6-22.用自旋锁来实现我们想要得到的同步效果

#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
atomic<int> a{0};
atomic<int> b{0};
int Thread1(int){
    int t = 1;
    a = t;
    b = 2;
}
int Thread2(int){
    while (b !=2 )
         ; // 自旋等待
    cout << "("<<a << "," << b << "}" << endl; // 总是等待a的值为1
}
int main(){
   thread t1(Thread1,0);
   thread t2(Thread2,0);
   t1.join();
   t2.join();
   cout << "Got (" << a <<","<< b << ")" << endl;
}

/*
   编译选项:g++ -std=c++11 6-3-5.cpp -lpthread
   代码清单: 6-22
   代码功能:用自旋锁来实现我们想要得到的同步效果
*/

6-23.用store函数中用松散的内存模型,这个指令可以任由编译器重排序或者由处理器乱序执行

#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
atomic<int> a{0};
atomic<int> b{0};
int ValueSet(int){
    int t = 1;
    a.store(t,memory_order_relaxed); // store的第一个参数表述要写入的值,第二个参数用的是memory_order_relaxed,表示松散的内存模型
    b.store(2,memory_order_relaxed);
}
int Observer(int){

    cout << "("<<a << "," << b << "}" << endl; // 可能有多种输出
}
int main(){
   thread t1(ValueSet,0);
   thread t2(Observer,0);
   t1.join();
   t2.join();
   cout << "Got (" << a <<","<< b << ")" << endl;
}

/*
   编译选项:g++ -std=c++11 6-3-4.cpp -lpthread
   代码清单: 6-23(可以比对代码6-21来看)
   代码功能:用store函数中用松散的内存模型,这个指令可以任由编译器重排序或者由处理器乱序执行
*/

6-24.用load来加载变量做自旋判断实现我们想要得到的同步效果

#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
atomic<int> a{0};
atomic<int> b{0};
int Thread1(int){
    int t = 1;
    a.store(t,memory_order_relaxed); // store的第一个参数表述要写入的值,第二个参数用的是memory_order_relaxed,表示松散的内存模型
    b.store(2,memory_order_relaxed);
}
int Thread2(int){
    while (b.load(memory_order_relaxed)!= 2 )
         ; // 自旋等待
    cout << "("<<a.load(memory_order_relaxed)<< "," << b << "}" << endl; // 总是等待a的值为1
}
int main(){
   thread t1(Thread1,0);
   thread t2(Thread2,0);
   t1.join();
   t2.join();
   cout << "Got (" << a <<","<< b << ")" << endl;
}

/*
   编译选项:g++ -std=c++11 6-3-5.cpp -lpthread
   代码清单: 6-24
   代码功能:用load来加载变量做自旋判断实现我们想要得到的同步效果
*/

6-25.memory_order_release和memory_order_acquire组合可实现一个较好的平衡

#include <thread>
#include <atomic>
#include <iostream>
using namespace std;
atomic<int> a{0};
atomic<int> b{0};
int Thread1(int){
    int t = 1;
    a.store(t,memory_order_relaxed); // store的第一个参数表述要写入的值,第二个参数用的是memory_order_relaxed,表示松散的内存模型
    b.store(2,memory_order_release); // memory_order_release表示本原子操作前所有的写原子操作必须完成
}
int Thread2(int){
    while (b.load(memory_order_acquire)!= 2 ) // memory_order_acquire表示本原子操作必须完成才能执行之后所有的读原子操作
         ; 
    cout << "("<<a.load(memory_order_relaxed)<< "," << b << "}" << endl;  // 1
}
int main(){
   thread t1(Thread1,0);
   thread t2(Thread2,0);
   t1.join();
   t2.join();
   cout << "Got (" << a <<","<< b << ")" << endl;
}

/*
   编译选项:g++ -std=c++11 6-3-8.cpp -lpthread
   代码清单: 6-25
   代码功能:memory_order_release和memory_order_acquire组合可实现一个较好的平衡
*/

6-26.本例中memory_order_consume比memory_order_acquire更slay一些,“先于发生的关系”被弱化

#include <thread>
#include <atomic>
#include <cassert>
#include <string>
using namespace std;
atomic<string*> ptr;
atomic<int> data;
void Producer(){
   string* p = new string("Hello");
   data.store(42,memory_order_relaxed);
   ptr.store(p,memory_order_release);
}

void Consumer(){
   string* p2;
   // memory_order_consume表示本线程中,所有后序的有关原子类型的操作,必须在本条原子操作完成之后执行
   while(!(p2 = ptr.load(memory_order_consume)))
    ;
    assert(*p2 == "hello");                        // 总是相等
    assert(data.load(memory_order_release) == 42); // 可能断言失败
}
int main(){
    thread t1(Producer);
    thread t2(Consumer);
    t1.join();
    t2.join();
    return 0;
}
/*
   编译选项:g++ -std=c++11 6-3-8.cpp -lpthread
   代码清单: 6-26
   代码功能:本例中memory_order_consume比memory_order_acquire更slay一些,“先于发生的关系”被弱化
*/

6-27.并不是所有的全局变量,静态变量都适合在多线程的情况下共享

#include <pthread.h>
#include <iostream>
using namespace std;
int errorCode = 0;
void* MaySetErr(void * input){
    if(*(int*)input == 1){
        errorCode = 1;
    }
    else if(*(int*)input == 2){
        errorCode = -1;
    }
    else 
        errorCode = 0;
}
int main(){
    int input_a = 1;
    int input_b = -1;
    pthread_t pthread1,pthread2;
    pthread_create(&pthread1,NULL,&MaySetErr,&input_a); 
    pthread_create(&pthread2,NULL,&MaySetErr,&input_b); 
    pthread_join(pthread1,NULL);
    pthread_join(pthread2,NULL);
    cout << errorCode << endl;
    return 0;
}
/*
   编译选项:g++ -std=c++11 6-4-1.cpp -lpthread
   代码清单: 6-27
   代码功能:并不是所有的全局变量和静态变量都适合在多线程的情况下共享
*/

6-28.展示用atexit注册的函数在程序以exit方式退出时都会被调用(调用次序与注册次序相反)

#include <cstdlib>
#include <iostream>
using namespace std;
void openDevice() { cout <<"device is opened" << endl;}
void resetDeviceStat(){ cout <<"device stat is reset" << endl;}
void closeDevice(){ cout <<"device id closed" << endl;}
int main(){
    atexit(closeDevice);
    atexit(resetDeviceStat);
    openDevice();
    exit(0);
}

/*
   编译选项:g++ -std=c++11 6-5-1.cpp
   代码清单: 6-29
   代码功能:展示用atexit注册的函数在程序以exit方式退出时都会被调用(调用次序与注册次序相反)
*/

6-29.多线程情况下可以向at_quick_exit注册快速退出的方法

#include <cstdlib>
#include <iostream>
using namespace std;
struct A{~A(){cout << "Destruct A. " << end;}}
void closeDevice(){cout << "device is closed" <<endl;}
int main(){
   A a;
   at_quick_exit(closeDevice);
   quick_exit(0);
   return 0;
}
/*
   编译选项:g++ -std=c++11 6-5-1.cpp
   代码清单: 6-29
   代码功能:多线程情况下可以向at_quick_exit注册快速退出的方法
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值