C++11新特性-常用

1.auto

它的功能为类型推断。auto是一个类型的占位符,通知编译器去根据初始化代码推断所声明变量的真实类型。各种作用域内声明变量都可以用到它。

auto i=42;                 //i is an int
auto l=42LL;              //l is an long long
auto p=new foo();      //p is a foo 

在遍历STL容器时需要声明迭代器(iterator),现在不需要声明typedef就可以得到简洁的代码了。

std::map<std::string,std::vector<int>> map;
for( auto it = begin(map); it != end(map); ++it ){}

需要注意的是,auto不能用来声明函数的返回值,但如果函数有一个尾随的返回类型时,auto可以出现在函数声明中返回值位置。在这种情况下,auto并不是告诉编译器去推断返回类型,而是指引编译器去函数的末端寻找返回值类型。

template< typename T1, typename T2>
auto compose( T1 t1, T2 t2) -> decltype( t1 + t2 )
{
    return t1+t2;
}
auto v = compose( 2, 3.14);  //v‘s type is double

2.nullptr

以前都是用0来表示空指针的,但由于0可以被隐式类型转换为整型,这就出现了一些问题。

void f( int );
void f( char * p );

如果存在以上两种方法,调用f(0)时,C++98编译失败,但在C++11中调用的是f(int)方法;想要调用f(char *p)调用方式为:f( nullptr )。

nullptr和任何指针类型以及类成员指针类型的空值之间可以发生隐式类型转换,同样也可以隐式转换为bool型(取值为false)。但是不存在到整型的隐式类型转换。

为了向前兼容,0仍然是个合法的空值指针。

3.Rang-based for loops(基于范围的for循环)

思考问题:对vector<int>中的每个元素加1。

void add( int & a)
{
    a += 1;
}
int intArray[] = {1,2,3,4,5};
vector< int > intVector(intArray,intArray+5);

第一种原始做法:

for(vector<int>::iterator iter = intVector.begin(); iter != intVector.end(); iter++ )
{
    add(*iter);
}

第二种使用boost的foreach:

#include <boost/foreach.hpp>
BOOST_FOREACH(int& a,intVector)
{
    add(a);
}

第三种使用for_each:

#include <algorithm>
for_each(intVector.begin(),intVector.end(),add);

第四种就是C++11扩展的for语句:

for( int& e : intArray )
{
  e = e+1;
}

用这种新的写法可以遍历数组、初始化列表以及任何重载了的非成员的begin和end函数的类型。

4.Override和final

vitual关键字是可选的,这使得阅读代码变得很费劲。因为可能需要追溯到继承体系的源头才能确定某个方法是否是虚函数。为了增加可读性,我总是在派生类里也写上virtual关键字。即使这样,仍然会产生一些微妙的错误。所以C++11加入了两个新的标识符。

override标识符:指定在基类中的虚函数应该被重写。

final标识符:指定派生类中的函数不会重写基类中的虚函数。

class B
{
public:
   virtual void f(int) {std::cout << "B::f" << std::endl;}
};

class D : public B
{
public:
   virtual void f(int)override final {std::cout << "D::f" << std::endl;}
};

class F : public D
{
public:
   virtual void f(int) {std::cout << "F::f" << std::endl;}
};

上述程序会报错:“D::f”声明为“final”的函数无法被“F::f”重写。

5.Stong-typed enums 强类型枚举

传统的C++枚举类型存在一些缺陷:它们会将枚举常量暴露在外层作用域中(这可能导致名字冲突,如果同一个作用域中存在两个不同的枚举类型,但是具有相同的枚举常量就会冲突),而且它们会被隐式转换为整型,无法拥有特定的用户定义类型。

enum A { a, b };        //默认从0开始赋值,依次加1
//enum B { a, c };      //报错a重定义:以前的定义为枚举数cout << a << "," << b ; //输出为0,1

在C++11中通过引入了一个称谓强类型枚举的新类型,修正了这种情况,强类型枚举由关键字enum class标识。它不会将枚举常量暴露到外层作用域中,也不会隐式的转换为整型,并且拥有用户指定的特定类型。

enum class A { a, b};
enum class B { a, c};   //不会报错
//cout << a <<endl;     //报错:a未声明的标识符
//cout << A::a <<endl;  //报错:<<没有找到接受A类型的右操作的运算符
cout << (int)A::a <<endl;  //输出0

6.Smart Pointers 智能指针

1)unique_ptr:如果内存资源的所有权不需要共享,就用这个(它没有拷贝构造函数),但是它可以转让给另一个unique_ptr(存在move构造函数)。

void foo(int* p)
{
    std::cout << *p << std::endl;
}
std::unique_ptr<int> p1(new int(42));     // 声明一个智能指针p1,初始化值为42
std::cout << * p1 << std::endl;           // 输出42
std::unique_ptr<int> p2 = std::move(p1);  // p1转让给p2,p1变为空,自动释放内存
//std::cout << * p1 << std::endl;         // 出错:程序被中断,因为p1已被置为空
std::cout << p1.get() << std::endl;       // 输出为00000000,get函数返回的是nullptr
std::cout << * p2 << std::endl;           // 输出42
(*p2)++;                                  // p2指向内容加1
if(p2)  foo(p2.get());                    // 输出43

2)shared_ptr:如果内存资源需要共享,那么使用这个。

void foo( int * p )
{
    cout << *p <<endl;
}
void bar( std::shared_ptr< int > p)
{
    ++(*p);
}
std::shared_ptr< int > p1( new int(42) );  //声明一个智能指针p2,初始化为42
std::shared_ptr< int > p2 = p1;            //把p1共享给p2
bar( p1 );                                 //改变p1的值,同时也在改变p2的值
foo( p2.get() );                           //输出为43

其中第一个声明也可以写成:

auto p3 = std::make_shared<int>(42);

make_shared<T>是一个非成员函数,使用它的好处是可以一次性分配共享对象和智能指针自身的内存。而显示地使用shared_ptr构造函数来构造至少需要两次内存分配。除了会产生额外的开销,还可能会导致内存泄漏。在下面的例子中,seed()抛出一个错误就会产生内存泄漏。

void foo( std::shared_ptr<int> p,int init )
{
    * p = init;
}
foo( std::shared_ptr<int>(new int(42)),seed());

3)weak_ptr:持有被shared_ptr所管理对象的引用,但是不会改变引用计数值。它被用来打破依赖循环(想象有一个tree结构中,父节点通过一个共享所有权的引用(chared_ptr)引用子节点,同时子节点又必须持有父节点的引用。如果这两个引用也共享所有权,就会导致一个循环,最终两个节点内存都无法释放)。

auto p = std::make_shared<int>(42);
std::weak_ptr<int> wp = p;   //wp只是获得了观测权,没有共享资源

auto sp = wp.lock();    //lock()从观测的shared_ptr获得一个可用的shared_ptr对象
std::cout << *sp << std::endl;

p.reset();      //reset()销毁函数

if(wp.expired())   //expired()==true表示wp所指对象已经销毁
    std::cout << "expired" << std::endl;

7.Lambdas(匿名函数)

语法形式:[函数对象参数](操作符重载函数参数) mutable或exception声明 -> 返回值类型{函数体}。

1)函数对象参数有以下几种形式:

空:没有使用任何函数对象参数。

=:函数体内可以使用Lambda所在作用范围内所有可见的局部变量,并且是值传递方式。

&:函数体内可以使用Lambda所在作用范围内所有可见的局部变量,并且是引用传递方式。

this:函数体内可以使用Lambda所在类中的成员变量。

a:将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的,要修改传递进来的a的拷贝,可以添加mutable修饰符。

&a:将a按引用进行传递。

a,&b:将a按值进行传递,b按引用进行传递。

=,&a,&b:除a和b按引用进行传递外,其他参数都按值进行传递。

&,a,b:除a和b按值进行传递外,其他参数都按引用进行传递。

2)操作符重载函数参数:没有参数时,这部分可以省略。 参数可以通过按值和按引用两种方试进行传递。

3)mutable或exception声明:这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝。exception声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用throw(int)。

4)->返回值类型:标识函数返回值的类型。当返回值为void,或者函数体中只有一处return的地方,这部分可以省略。

5)函数体:标识函数的实现,这部分不能省略,但函数体可以为空。

vector<int> iv{5, 4, 3, 2, 1};
int a = 2, b = 1;

for_each(iv.begin(), iv.end(), [b](int &x){cout<<(x + b)<<endl;}); // 输出6 5 4 3 2
for_each(iv.begin(), iv.end(), [=](int &x){x *= (a + b);});     // iv每个数乘以3for_each(iv.begin(),iv.end(),[](int &x){cout<<x<<endl;});      //输出15 12 9 6 3
for_each(iv.begin(), iv.end(), [=](int &x)->int{return x * (a + b);}); //只是返回每个数的3倍,但是不改变原来数组的数 for_each(iv.begin().iv.end(),[](int &x){cout<<x<<endl;});    //输出为15 12 9 6 

再举一个例子:

std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);

std::for_each(std::begin(v), std::end(v), [](int n) {std::cout << n << std::endl;});  //输出为1 2 3

auto is_odd = [](int n) {return n%2==1;};    //定义了一个函数is_odd,返回1(不能够被2整数)或0(能被2整数)
auto pos = std::find_if(std::begin(v), std::end(v), is_odd); //find_if查找符和条件的数据,返回指向数据的指针
if(pos != std::end(v))
std::cout << *pos << std::endl;  //第一个符合条件的数据为1,输出为1

更复杂的是递归lambda。

std::function<int(int)> lfib = [&lfib](int n) {return n < 2 ? 1 : lfib(n-1) + lfib(n-2);};
cout<<lfib(5)<<endl;;

(暂时更新到这里,后续会继续更新)

时间: 2024-08-27 03:42:19

C++11新特性-常用的相关文章

C++11 新特性之 变长参数模板

template <typename ... ARGS> void fun(ARGS ... args) 首先明确几个概念 1,模板参数包(template parameter pack):它指模板参数位置上的变长参数,例如上面例子中的ARGS 2,函数参数包(function parameter pack):它指函数参数位置上的变长参数,例如上面例子中的args 一般情况下 参数包必须在最后面,例如: template <typename T, typename ... Args>

C++ 11新特性解析——《深入理解C++ 11:C++11新特性解析和应用》读书笔记

因为偶然的机会,在图书馆看到<深入理解C++ 11:C++11新特性解析和应用>这本书,大致扫下,受益匪浅,就果断借出来,对于其中的部分内容进行详读并亲自编程测试相关代码,也就有了整理写出这篇读书笔记的基础.C++作为踏入编程的最初语言,一直充满感情,而C++11作为新标准虽然推出一段时间了,却因为总总原因直到现在才去开始真正了解,不过一句话回荡在脑中:当你认为为时已晚的时候,恰恰是最早的时候!从C++98到C++11, C++11标准经历了10几年的沉淀,以全新的姿态迎接新的挑战,长话短说,

C++11——新特性总结

前言: 开学过去一个半月了,说来十分惭愧,由于和女友最后还是分开了,导致这段时间一直在沉沦,每天晚上回去打打lol或者cs,就睡觉,基本上把我自己定下的自学目标给抛弃了.好在这段时间里还是凭借以前的基础投了不少岗位,也笔试了不少公司,基本都通过了笔试.第一次面试是网易,结果在最后一轮的技术面上挂了下来.其实回想起来,当时问的问题我其实之前都有仔细的专研过,只不过时间太久忘了罢了.这也要怪我自己准备不够充分.之前腾讯的笔试,我其实感觉自己是做砸了的,不过没想到还是得到了面试机会,就在两天之后的下午

C++11 新特性之 tuple

我们在C++中都用过pair.pair是一种模板类型,其中包含两个数据值,两个数据的类型可以不同.pair可以使用make_pair构造 pair<int, string> p = make_pair(1, "a1"); 如果传入的参数为多个,那么就需要嵌套pair,如下代码 #include <iostream> #include <map> using namespace std; int main() { //<int, string,

【C++11】30分钟了解C++11新特性

作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明.如果你喜欢这篇文章,请点[推荐].谢谢! 什么是C++11 C++11是曾经被叫做C++0x,是对目前C++语言的扩展和修正,C++11不仅包含核心语言的新机能,而且扩展了C++的标准程序库(STL),并入了大部分的C++ Technical Report 1(TR1)程序库(数学的特殊函数除外). C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decl

[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() { p

C++11 新特性(5) 统一初始化

在C++11之前,初始化的类型并非总是统一的. 例如以下两个man定义,一个作为结构,一个作为类.两者的初始化是不一样的. #include <iostream> using namespace std; struct manStruct{ string name; int age; }; class manClass { private: string name; int age; public: manClass(string s,int a):name(s),age(a){ } }; i

[cocos2d-x] 一些C++ 11新特性的引入

1.auto关键字的使用 auto关键字原理     在定义变量的时候必须申明类型,c++是强语言类型,在编译阶段需要知道类型,这样的好处是程序效率更高,而动态语言不需要类型申明的需要自推导变量类型.使用了auto是不是c++效率会变慢?完全不是,因为在编译阶段编译器已经帮程序员推导好了变量的类型.前提条件是编译器可以根据当前的程序的状态推导出变量类型.只是编译器更加智能,可能会增加编译工作,但是不会影响运行效率. 实例1:申明普通变量 auto num = 10; 实例2: vector<st

c++11 新特性之 auto关键字

C++11是对目前C++语言的扩展和修正.C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto.decltype,和模板的大量改进. g++编译c++11命令加上 -std=c++11 C++11中引入auto第一种作用是为了自动类型推导 auto的自动类型推导,用于从初始化表达式中推断出变量的数据类型.通过auto的自动类型推导,可以简化我们的编程工作 auto实际上实在编译时对变量进行了类型推导,所以不会对程序的运行效率造成不良影响另外,似乎auto并不会影响编译速度,