C++11新特性之新类型与初始化
这是C++11新特性介绍的第一部分,比较简单易懂,但是也有一些有趣的地方。
不想看toy code的读者可以直接拉到文章最后看这部分的总结。
新类型
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空间。
nullptr字面量
C++11标准中专门为空指针增加了nullptr字面量,同时不推荐再使用NULL或者0表示空指针。
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是一样的。
constexpr
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。
来源:一根笨茄子的博客