神刀安全网

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

这是C++11新特性介绍的第一部分,比较简单易懂,但是也有一些有趣的地方。不想看toy code的读者可以直接拉到文章最后看这部分的总结。

新类型

long long类型

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

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表示空指针。

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用于声明常量表达式,编译器会验证此变量的值是否是一个常量表达式。

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 ∈_j is not a constexpr;
//int in_j = 0;
//constexpr int *p5 = ∈_j;

值得注意的是,constexpr指针可以指向非常量变量,只要此变量定义于函数之外,因为这样的变量的指针(地址)是可以在编译期确定的。

另外,下面的constexpr指针与const指针的含义是完全不同的:

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语句

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承诺不抛出异常的函数实际抛出了异常,那么程序会直接终止。

void no_except() noexcept
{

throw 1;
}
// the following call will cause terminate
//no_except();

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

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

将noexcept运算符,结合带参数的noexcept指示符,可以得到如下常用法:

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

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

初始化

列表初始化

C++11新标准中为很多类型增加了列表初始化的功能。

可以用列表初始化一个简单变量。

int single_int1 = 0;
int single_int2 = {0};
cout<<"test list initialization:/n"<<single_int1<<'/t'<<single_int2<<endl;

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

// 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动态分配内存时使用列表初始化。

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;

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

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标准中允许直接对类内成员进行初始化/列表初始化。

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();

总结

  1. long long类型。
  2. nullptr字面量用于表示空指针。
  3. constexpr用于表示常量表达式。
  4. noexcept可以用于指示一个函数是否会抛出异常,同时可以用作运算符判定一个函数是否承诺不抛出异常。
  5. 新增基础类型、容器类型、new分配内存时的列表初始化。构建临时变量时也可以直接使用列表初始化。
  6. 可以直接对类内成员进行初始化/列表初始化。

完整代码详见 new_type_and_keywords.cppinitialize.cpp

欢迎关注我的微信公众号TechTalking,技术·生活·思考:

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

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » C++11新特性之新类型与初始化

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址