[C++11新特性]第二篇

0.可变数量参数,可变函数模版,变长模版类

  • c++98可变数量参数

#include<cstdio>

#include<cstdarg>

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));

    return 0;

}
  • 可变函数模版

#include<iostream>

#include<stdexcept>

using namespace std;

void Print(const char *s)

{

    while(*s){

        if(*s=='%'&&*++s!='%')

            throw runtime_error{"missing arguments"};

        cout<<*s++;

    }

}

template<typename T,typename...Args>

void Print(const char*s,T value,Args...args)

{

    while(*s)

    {

        if(*s=='%'&&*++s!='%')

        {

            cout<<value;

            return Print(++s,args...);

        }

        cout<<*s++;

    }

    throw runtime_error{"extra arguments provided to Print"};

}

int main()

{

    Print("hello %s\n",string("world"));

    return 0;

}
  • 变长模版类

#include<iostream>

using namespace std;



template<long...nums> struct Multiply;



template<long first,long ...last>

struct Multiply<first,last ...>

{

    static const long val=first*Multiply<last...>::val;

};

template<>

struct Multiply<>

{

    static const long val=1;

};

int main()

{

    cout<<Multiply<2,3,4,5>::val<<endl;

    cout<<Multiply<22,44,66,88,9>::val<<endl;

    return 0;

}

1.C++11原子类型

在并行编程、多线程编程中,对于共享资源的访问,需要通过添加互斥锁的方法来保证正确性。在POSIX标准下,pthread库,我们用lock方法来实现,如下:

pthread_mutex_t m=PTHREAD_MUTEX_INITIALIZER;



void* func(void*)

{

    long long i;

    for(i=0;i<10000000;i++)

    {

        pthread_mutex_lock(&m);

        total+=i;

        pthread_mutex_unlock(&m);

    }

}

而在c++11中,我们通过定义的原子类型即可很方便地实现。c++11定义很多原子数据类型,比如:atomic_bool,atomic_char,atomic_int等等。

//total定义为原子类型,c++11中不需要为原子类型声明互斥锁

atomic_llong total{0};

void func(int)

{

    for(long long i=0;i<100000;i++)

        total+=i;

}

2.内存模型,顺序一致性与memory_order

太复杂,主要是硬件平台下内存读写顺序一致性.在c++11中,实现了很多内存顺序的细节,比如顺序一致、松散、release-require、release-consume四种顺序模型。

3.线程局部存储

本节省略…….

4.指针空值

        在良好的编程习惯中,声明一个变量时,同时初始化,在以前的习惯里,如果声明指针,一般初始化为0或NULL。

其中NULL为宏定义,在stddef.h中可见细节,一般被定义为0或(void*)常量。

在c++11中,定义了一个指针空值类型的常量:nullptr,大小和void*一致。另有nullptr_t常量。

5.默认函数的控制

在c++中声明自定义类,编译器会自动生成默认函数:构造函数、拷贝构造函数、拷贝赋值函数、移动构造函数、移动拷贝函数、析构函数。

还会自动生成默认操作符:operator,,operator&,operator&&,operator*,operator->,operaotr->*,operator new,operator delete.

在以前的c++编程规则中,如果我们指定带参数的构造函数,则需要重写不带参数,即默认构造函数。

class TwoCstor

{

    //提供了带参数的构造函数,则必须自行提供不带参数的版本

    public:

        TwoCstor(){};

        TwoCstor(int i):data(i){};

    private:

        int data;

}

在C++11中,通过default关键字来实现这个目标。如下:

class TwoCstor2

{

    //提供了带参数的构造函数,再指示编译器提供默认版本

    public:

        TwoCstor2()=default;

        TwoCstor2(int i):data(i){};

    private:

        int data;

}

        在实现Singleton模式中,我们需要将拷贝构造函数设为私有,在c++11中则更简单,直接利用deleted关键字,指示编译器不生成函数的默认版本。

#include<type_traits>

#include<iostream>

using namespace std;

class NoCopyCstor

{

    public:

        NoCopyCstor()=default;

        //通过使用"=delete"有效阻止用户错用拷贝构造函数

        NoCopyCstor(const NoCopyCstor &)=delete;

};

int main()

{

    NoCopyCstor a;

    NoCopyCstor b(a);//无法通过编译

}

6.lambda函数

lambda函数的语法定义如下:

     [capture](parameters) mutable –>return-type {statement}

使用lambda函数作为stable_sort函数的调用对象。

int main()

{

    vector<string> strVec{"hello","wo","panzg1","at3","binary_function"};

    stable_sort(strVec.begin(),strVec.end(),

        [](const string &a,const string &b){return a.size()<b.size();});

    for(auto e : strVec)

        cout<<e<<endl;

}

code…各种各样的lambda函数

捕获列表的常见几种形式:

  • [var] 值传递捕获var
  • [=]值传递方式捕获所有父作用域的变量,包括this
  • [&var]引用传递捕获var
  • [&]引用传递捕获所有父作用域的变量,包括this
  • [this] 值传递方式捕获当前this指针

值传递、引用传递可以混用,比如[=,&a,b]等等。

仿函数,functor,函数对象,就i是重定义了成员函数operator()的一种自定义类型对象。比如在下面的例子中,test不是一样函数,而是一个对象。仿函数广泛地被用在STL中,在c++11中lambda也要被广泛使用。

#include<iostream>

class _functor

{

    public:

        int operator()(int x,int y) {return x+y;}

};

int main()

{

    _functor test;

    int x=3,y=4;

    std::cout<<test(3,4);

}

事实上,仿函数是编译器实现lambda的一种方式,在现阶段,通常编译器会把lambda函数转化为一个仿函数对象。

关于lambda和STL的联系,它使得STL的算法使用更加方便,比如for_each,其原型是:

UnaryProc for_each(InputIterator beg,InputIterator end,UnaryProc op)

for_each算法第三个参数是一个单个参数的“函数”,即一个函数指针、仿函数或者lambda函数。

函数指针方法的缺陷是:往往定义在别的地方,阅读代码不方便;如果不进行inline优化,性能就比lambda函数差很多。而且函数指针的应用范围小很多,相比函数指针、仿函数,lambda函数往往是最佳的选择。

注:在c++98中,STL帮助我们定义了很多仿函数可直接使用。

你可能感兴趣的:(C++)