C++ 11 的一些重要新特性

构造函数

class IntCell
{
public:
    explicit IntCell(int initialVaule = 0): storedValue{initialValue} {}
    int read() const {return storedValue;}
    void write(int x) {storedValue = x;}

private:
    int storedValue;
};

初始化列表

当数据成员是类时,使用初始化列表而不是在函数体内赋值可以节省时间。而且以下两种情况只能使用初始化列表:
1. 数据成员是const类型
2. 如果数据成员是个类,这个类没有zero-parameter构造函数,即默认构造函数,只能使用初始化列表。

在C++11中用花括号代替括号来初始化。

explicit

你应该将所有的只有一个参数的构造函数设成explicit避免类型转化。

通常一个参数的构造函数定义了一个隐藏的类型转化。

IntCell obj;
obj = 37;

其实是这样的:

IntCell temporary = 37;
obj = temporary;

temporary的初始化会用到一个参数的构造函数,如果使用了explicit就可以避免这种转化。

声明

下面是正确的:

IntCell obj1; // Zero parameter constructor
IntCell obj2( 12 ); // One parameter constructor

下面是不正确的:

IntCell obj3 = 37; // Constructor is explicit,要使用()
IntCell obj4( ); // Function declaration

而obj4就是一个函数声明,零参数,返回值是IntCell,这也是使用花括号初始化的原因之一,虽然初始化列表中可以使用括号初始化零参数,但是有点丑。

IntCell obj1; // Zero parameter constructor, same as before
IntCell obj2{ 12 }; // One parameter constructor, same as before
IntCell obj4{ }; // Zero parameter constructor

右值引用

在C++ 11 以前引用只有左值引用,左值是一个非临时对象。

string str = "hell";
string & rstr = str;    // rstr is another name for str
rstr += ’o’;    // changes str to "hello"
bool cond = (&str == &rstr);    // true; str and rstr are same object
string & bad1 = "hello";    // illegal: "hello" is not a modifiable lvalue
string & bad2 = str + "";   // illegal: str+"" is not an lvalue
string & sub = str.substr( 0, 4 );  // illegal: str.substr( 0, 4 ) is not an lvalue

右值引用由&&表示:

string str = "hell";
string && bad1 = "hello";   // Legal
string && bad2 = str + "";  // Legal
string && sub = str.substr( 0, 4 );     // Legal

左值引用经常用在下面几个方面:

  • 关联复杂的名字
auto & whichList = theLists[ myhash( x, theLists.size( ) ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( x );

如果只写成:

auto whichList = theLists[ myhash( x, theLists.size() ) ];

witchList只是一个拷贝,不能使用push_back 之类的操作。

  • 在循环中
for( int i = 0; i < arr.size( ); ++i )
++arr[ i ];

上面的代码可以写成:

for ( auto & x: arr )
    ++x;
  • 避免拷贝比较大的对象

例如在函数返回值是个比较大的对象,但是并不改变这个对象,我们可以返回这个对象的引用。

在C++中参数传递通常是值传递

一般遵循下面的原则:

  1. 如果是个小对象,在函数中不需要改变,采用值传递(call-by-value)。
  2. 如果是个比较大的对象,在函数中不需要改变,采用常量引用(call-by-constant-reference)。
  3. 如果传递的对象需要改变,采用引用(call-by-reference)。

请看下面的例子:

double average( double a, double b ); // returns average of a and b
void swap( double a, double b ); // swaps a and b; wrong parameter types
string randomItem( vector<string> arr ); // returns a random item in arr; inefficient

上面的代码应该改成:

double z = average( x, y );
void swap( double & a, double & b );
string randomItem( const vector<string> & arr );

我们来看关于返回值方面的,下面有三个函数:

double average( double a, double b );   // returns average of a and b
LargeType randomItem( const vector<LargeType> & arr );  // potentially inefficient
vector<int> partialSum( const vector<int> & arr );  // efficient in C++11

将第二个函数进行改变,使之更有效率:

LargeType randomItem1( const vector<LargeType> & arr )
{
    return arr[ randomInt( 0, arr.size( ) - 1 ) ];
}
const LargeType & randomItem2( const vector<LargeType> & arr )
{
    return arr[ randomInt( 0, arr.size( ) - 1 ) ];
}
vector<LargeType> vec;
...
LargeType item1 = randomItem1( vec ); // copy
LargeType item2 = randomItem2( vec ); // copy
const LargeType & item3 = randomItem2( vec ); // no copy

注意item2还是进行了拷贝,只有item3没有拷贝,如果返回值是常量引用,那么变量也要是常量引用才不会拷贝。

来看第三个函数:

vector<int> partialSum( const vector<int> & arr )
{
    vector<int> result( arr.size( ) );
    result[ 0 ] = arr[ 0 ];
    for( int i = 1; i < arr.size( ); ++i )
    result[ i ] = result[ i - 1 ] + arr[ i ];
    return result;
}
vector<int> vec;
...
vector<int> sums = partialSum( vec ); // Copy in old C++; move in C++11

在C++ 11中,如果返回的是一个右值,会使用move来提高效率。

来看第一个函数:

void swap( double & x, double & y )
{
    double tmp = x;
    x = y;
    y = tmp;
}
void swap( vector<string> & x, vector<string> & y )
{
    vector<string> tmp = x;
    x = y;
    y = tmp;
}

因为xy都是左值,所以不会像第二个函数一样用move进行传递。但是我们可以使用cast来将右边的值看做右值:

void swap( vector<string> & x, vector<string> & y )
{
    vector<string> tmp = static_cast<vector<string> &&>( x );
    x = static_cast<vector<string> &&>( y );
    y = static_cast<vector<string> &&>( tmp );
}

但是static_cast的语法比较复杂,标准库中的函数std::move可以实现:

void swap( vector<string> & x, vector<string> & y )
{
    vector<string> tmp = std::move( x );
    x = std::move( y );
    y = std::move( tmp );
}

未完,在学习中不断地增加。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值