C++11新特性之新类型与初始化

C++11新特性之新类型与初始化

snoone | 2016-06-23 11:57    浏览量(148)    评论(0)    推荐(0)

这是C++11新特性介绍的第一部分,比较简单易懂,可是也有一些有趣的地方。html

不想看toy code的读者能够直接拉到文章最后看这部分的总结。git

新类型github

long long类型函数

C++11标准中新加入了long long类型属性,占用空间不小于long类型。测试代码以下:测试

1
2
3
4
long  large = LONG_MAX;
long  long  long_large = LLONG_MAX;
long  long  long_long_large = 1LL << 63;
cout<< "test long long:" <<large<< '\t' <<long_large<< '\t' <<long_long_large<<endl;

在个人机器上实测,long long类型和long类型一样使用64bit空间。spa

nullptr字面量指针

C++11标准中专门为空指针增长了nullptr字面量,同时不推荐再使用NULL或者0表示空指针。code

1
2
3
4
int  *p1 = nullptr;
int  *p2 = 0;
int  *p3 = NULL;
cout<< "test nullptr: " <<(p1 == p2)<< '\t' <<(p1 == p3)<<endl;

最终测试结果,nullptr和NULL和0是同样的。orm

constexprhtm

C++11标准中新增constexpr用于声明常量表达式,编译器会验证此变量的值是不是一个常量表达式。

1
2
3
4
5
6
7
8
9
10
11
12
13
int  out_i = 0;  // out_i定义于函数外部
...
constexpr  int  mf = 20;
constexpr  int  limit = mf + 1;
constexpr  int  *p4 = &out_i;
// the following would cause a make error 
 
// since large is not a constexpr
//constexpr int wrong = large + 1; 
 
// since &in_j is not a constexpr;
//int in_j = 0;
//constexpr int *p5 = &in_j;

值得注意的是,constexpr指针能够指向很是量变量,只要此变量定义于函数以外,由于这样的变量的指针(地址)是能够在编译期肯定的。

另外,下面的constexpr指针与const指针的含义是彻底不一样的:

1
2
3
constexpr  int  *p6 = nullptr;  // a const pointer point to an int
// p6 = &out_i; // error: p6 is a constexpr
const  int  *p7 = nullptr;  // a pointer point to a const int

第一个指针表示一个常量指针,即指针的值是常量;而第二个指针表示一个指向const int的指针,即指针指向的值是常量。

constexpr还能够用于函数,constexpr函数是指能用于常量表达式的函数,它遵循如下几条约定:

a.返回类型是字面值类型

b.形参类型是字面值类型

c.函数体中必须有且仅有一条return语句

1
2
3
4
5
6
constexpr  int  sz() {  return  42; }
constexpr  int  new_sz( int  cnt) {  return  sz() * cnt; }
constexpr  int  size = sz();
constexpr  int  nsize = new_sz(mf);
//constexpr int wrong_size = new_sz(out_i); // error: out_i is not a constexpr
cout<< "test constexpr: " <<mf<< '\t' <<limit<< '\t' <<p4<< '\t' <<size<< '\t' <<nsize<< '\t' <<p6<< '\t' <<p7<<endl;

noexcept

noexcept能够用做异常指示符,用于指示一个函数是否会抛出异常。编译器并不检查使用了noexcept的函数是否真的不抛出异常,在运行时,若是一个使用noexcept承诺不抛出异常的函数实际抛出了异常,那么程序会直接终止。

1
2
3
4
5
6
void  no_except() noexcept
{
     throw  1;
}
// the following call will cause terminate
//no_except();

noexcept还能够带参数,noexcept(true)表示不会抛出异常,noexcept(false)表示可能抛出异常。

同时noexcept还能够用做运算符,接受一个函数调用,返回一个bool值表示是否会抛出异常。noexcept运算符并不会对其实参进行求值。

将noexcept运算符,结合带参数的noexcept指示符,能够获得以下经常使用法:

1
2
void  no_except2() noexcept(noexcept(no_except())){}
cout<< "test noexcept: " <<noexcept(no_except())<< '\t' <<noexcept(no_except2())<<endl;

这种用法表示no_except2和no_except的异常说明保持一致。

初始化

列表初始化

C++11新标准中为不少类型增长了列表初始化的功能。

能够用列表初始化一个简单变量。

1
2
3
int  single_int1 = 0;
int  single_int2 = {0};
cout<< "test list initialization:\n" <<single_int1<< '\t' <<single_int2<<endl;

能够用列表初始化一个容器(vector,list,map,set…)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// vector/list list initialization
vector<string> v1 = { "ab" "cd" "ef" };
list<string> l2{ "gh" "ij" "kl" };
//vector<string> v3("mn", "op", "qr"); // wrong initialization format
cout<< "test vector/list list initialization:\n" <<v1[1]<< '\t' <<l2.front()<<endl;
 
// map/set list initialization
map<string, string> m1 =
{
     { "a" "A" },
     { "b" "B" },
     { "c" "C" }
};
m1.insert({ "d" "D" });
set<string> s1 = { "a" "b" "c" };
cout<< "test map/set list initialization:\n" <<m1[ "d" ]<< '\t' <<*s1.find( "b" )<<endl;

能够在使用new动态分配内存时使用列表初始化。

1
2
3
vector< int > *pv =  new  vector< int >{0, 1, 2, 3, 4};
int  *pi =  new  int [5]{0, 1, 2, 3, 4};
cout<< "test new alloator using list initialization:\n" <<(*pv)[2]<< '\t' <<pi[2]<<endl;

能够在传入参数/函数返回值时使用列表初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
m1.insert({ "d" "D" });
 
vector<string> error_msg( int  typ)
{
     switch (typ)
     {
         case  1:
             return  { "type1" "msg1" };
         case  2:
             return  { "type2" "msg2" };
         default :
             return  {};
     }
}
 
pair<string, string> get_pair( int  typ)
{
     if (typ == 1)  return  { "key" "value" };
     return  pair<string, string>( "default key" "default value" );
}
 
vector<string> err_msg1 = error_msg(1);
vector<string> err_msg2 = error_msg(2);
vector<string> err_msg3 = error_msg(3);
cout<< "test return value list initialization:\n" <<err_msg1[1]<< '\t' <<err_msg2[1]<< '\t' <<err_msg3.empty()<<endl;
 
pair<string, string> p1 = get_pair(1);
pair<string, string> p2 = get_pair(2);
cout<< "test return pair list initialization:\n" <<p1.first<< '\t' <<p2.first<<endl;

类内成员初始化

C++11标准中容许直接对类内成员进行初始化/列表初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class  InitClass
{
     public :
         void  print_class()
         {
             cout<<field1<< '\t' <<field2<< '\t' <<field3<< '\t' <<field4<<endl;
         }
     private :
         int  field1 = 1;
         int  field2;
         double  field3 = 1.0;
         double  field4;
};
 
class  InitClassMgr
{
     public :
         vector<InitClass> init_objs = {InitClass()};
};
 
InitClass test_class;
cout<< "test class member initialization:\n" ;
test_class.print_class();
 
InitClassMgr mgr;
cout<< "test class member of class type initialization:\n" ;
mgr.init_objs[0].print_class();

总结

· long long类型。

· nullptr字面量用于表示空指针。

· constexpr用于表示常量表达式。

· noexcept能够用于指示一个函数是否会抛出异常,同时能够用做运算符断定一个函数是否承诺不抛出异常。

· 新增基础类型、容器类型、new分配内存时的列表初始化。构建临时变量时也能够直接使用列表初始化。

· 能够直接对类内成员进行初始化/列表初始化。

完整代码详见new_type_and_keywords.cpp initialize.cpp

来源:一根笨茄子的博客