技术开发 频道

三驾马车并驾齐驱 C++能否重焕青春

        【IT168 技术】Java十几年来的迅猛发展,似乎在印证一个亘古不变的真理——与时俱进。C语言几年来也在不断发力,作为变种,Object C在Apple应用领域如火如荼,而作为编程语言前三甲的C++,似乎低调了许多,尽管C++阵营甚至没有一个完整的标准,C++ 11的推出,必定会把这款“老”编程语言带到一个新的高度。正如C++之父Bjame Stroustrup说的那样,C++11就像一个新语言。的确,C++11的核心已经发生了巨大的变化,它现在支持Lambda表达式,对象类型自动推断,统一的初始化语法,委托构造函数,deleted和defaulted函数声明nullptr,以及最重要的右值引用。这篇文章会介绍C++11核心语言的一些突出特性。

  Lambda表达式

  Lambda表达式允许在调用处定义函数。 Lambda表达式的格式如下:

 [capture](parameters)->return-type {body}

  []里是函数调用的参数列表,表示一个Lambda表达式的开始。举个例子,for_each函数要求用户提供一个表明“行为”的函数对象。以vector为例,如果想使用for_each对其中的各元素全部赋值为 true,一般需要下列函数对象。

class filler

  {

  
public : void operator ()( bool

  
& i) const {i = true ;}

  } ;

  这样做的缺陷是麻烦,不直观。而如果使用lambda,一切变得简单许多。以boost.lambda为例,刚才的问题可以这么解决:

for_each(v.begin(), v.end(), _1 = true );

  自动类型推断

  C++11借助auto关键字允许你声明对象时不指定类型。

auto x=0; //x has type int because 0 is int

  auto c
='a'; //char

  auto d
=0.5; //double

  auto national_debt
=14400000000000LL;//long long

  统一初始化语法

  老的C++至少有4个不同的初始化符号,包括:小括号初始化,“=”符号初始化,大括号初始化,构造函数初始化。有些存在重叠,容易引起混乱。为保持一致,C++11统一使用大括号符号。

class C

  {

  
int a;

  
int b;

  
public:

  C(
int i, int j);

  };

  C c {
0,0}; //C++11 only. Equivalent to: C c(0,0);

  
int* a = new int[3] { 1, 2, 0 }; /C++11 only

  
// C++11 container initializer

  vector vs
={ "first", "second", "third"};

  map singers
=

  { {
"Lady Gaga", "+1 (212) 555-7890"},

  {
"Beyonce Knowles", "+1 (212) 555-0987"}};

  class X

  {

  
int a[4];

  
public:

  X() : a{
1,2,3,4} {} //C++11, member array initializer

  };

  class Y

  {

  
int a=7; //C++11 only

  
public:

  Y();

  };

  

        Defaulted 与 Deleted对比(Defaulted vs Deleted)

  我们知道C++的编译器在你没有定义某些成员函数的时候会给你的类自动生成这些函数,比如,构造函数,拷贝构造,析构函数,赋值函数。有些时候,我们不想要这些函数,比如,构造函数,因为我们想做实现单例模式。传统的做法是将其声明成private类型。

  在新的C++ 11中引入了两个指示符,delete意为告诉编译器不自动产生这个函数,default告诉编译器产生一个默认的。下面给两个例子

  default

  struct A

  {

  A()
=default; //C++11

  
virtual ~A()=default; //C++11

  };

  
int func()=delete;

  再如delete

struct NoCopy

  {

  NoCopy
& operator =( const NoCopy & ) = delete;

  NoCopy (
const NoCopy & ) = delete;

  };

  nullptr

  null和文字0被用来作为空指针替代品有多年历史。C++ 11终于有一个关键字指定一个空指针常量nullptr了,nullptr是一个强类型。nullptr适用于所有指针类别,包括函数指针和成员指针:

 const char *pc=str.c_str(); //data pointers

  
if (pc!=nullptr) //C++11

  cout
<

  
int (A::*pmf)()=nullptr; //pointer to member function

  
void (*pmf)()=nullptr; //pointer to function

  委托构造函数

  在以前的C++中,构造函数之间不能互相调用,我们通常会把相同的代码放到一个私有的成员函数中。 

class SomeType {

  
private:

  
int number;

  
string name;

  SomeType(
int i, string& s ) : number(i), name(s){}

  
public:

  SomeType( ) : SomeType(
0, "invalid" ){}

  SomeType(
int i ) : SomeType( i, "guest" ){}

  SomeType(
string& s ) : SomeType( 1, s ){ PostInit(); }

  };

  新的C++11支持委托构造函数,说白了,其实就是在某一个构造函数中调用另外一个构造函数,实际上,类似的特性在Java中早已经存在了。 

class BaseClass

  {

  
public:

  BaseClass(
int iValue);

  };

  
class DerivedClass : public BaseClass

  {

  
public:

  
using BaseClass::BaseClass;

  };

  上例中,派生类手动继承基类的构造函数,编译器可以使用基类的构造函数完成派生类的构造。

  右值引用和move语义

  在老版的C++中,临时性变量(称为右值”R-values”,位于赋值操作符之右)经常用作交换两个变量。比如下面的示例中的tmp变量。示例中的那个函数需要传递两个string的引用,但是在交换的过程中产生了对象的构造,内存的分配还有对象的拷贝构造等等动作,成本比较高。

void naiveswap(string &a, string &b)

  {

  
string temp = a;

  a
=b;

  b
=temp;

  }

  C++ 11增加一个新的引用(reference)类型称作右值引用(R-value reference),标记为typename &&。他们能够以non-const值的方式传入,允许对象去改动他们。这项修正允许特定对象创造出move语义。

 class string

  {

  
string (string&&); //move constructor

  
string&& operator=(string&&); //move assignment operator

  };

  能过右值引用,string的构造函数需要改成“move构造函数”,如下所示。这样一来,使得对某个stirng的右值引用可以单纯地从右值复制其内部C-style的指针到新的string,然后留下空的右值。

  相比起来,C++ 11减少了临时变量带来的内存非配与销毁开销,更有效率。

  总之,C++11 还是很像学院派,很多实用的东西还是没有,比如: XML,sockets,reflection,当然还有垃圾回收,如果你不小心没管住内存,那么就要对不起了,内存崩溃的情况不是不可能。在Java和.NET都支持垃圾回收之后,C++ 11还是显得有些另类。

0
相关文章