本周主要看了1-4章,大部分都掠过了,对于那些头一次见的东西,想到的东西,记录如下,其中很多内容是c++11中新加的特性,所以在编译时要加参数-std=c++11。
1.列表初始化(list-initialization)(P43,P63)
这种写法来源于对数组以及数据结构的初始化,如:int a[3] = {0,1,2};
从c++98开始,可以用于单值得赋值,如:int b = {4};
c++11开始,支持可以省略等号。当大括号中没有值得时候,变量将要被初始化为0.
例如:int a{3} 等价于 int a = 3 等价于 int a = {3};
这种写法只能用于c++11标准,所以在编译时候必须加上-std=c++11
优点:有助于防范类型转换错误
具体就是:列表初始化不允许缩窄(narrowing),即变量可能无法表示赋给它的值。
举例说:
测试代码:如果用int a = 1.1;
那最终编译过程中只会报出一个警告信息,但是最终还是可以生成可执行文件。
main.cpp:22:11: warning: implicit conversion from 'double' to 'int' changes value from 1.1 to 1 [-Wliteral-conversion] int a = 1.1; ~ ^~~ 1 warning generated.
如果使用int a {1.1};
则会报错误,导致无法编译通过
main.cpp:21:11: error: type 'double' cannot be narrowed to 'int' in initializer list [-Wc++11-narrowing] int a {1.1}; ^~~
main.cpp:21:11: note: override this message by inserting an explicit cast int a {1.1}; ^~~ static_cast<int>( )
main.cpp:21:11: warning: implicit conversion from 'double' to 'int' changes value from 1.1 to 1 [-Wliteral-conversion] int a {1.1}; ~^~~ 1 warning and 1 error generated.
2.打印进度;
之前一直好奇一些程序的进度是怎么打印的,比如rsync文件过程中的百分比,这些数据不是按行打印的,而是在原地变化,现在终于搞懂这个是怎么搞的了,其实很简单,就是用了转义字符\r 回车符合,其实回车和换行还是有区别的,但是以前都是知其然而不知其所以然。具体可以参考程苓峰的这篇blog:《回车和换行》
代码如下:
1 #include <iostream>
3.auto声明(P66)
auto声明可以让编译器根据其初始值的类型来推断变量的类型,auto起源于c语言,但是很少使用
例如:auto a = 100 a会被编译器初始化为int类型
auto b = 1.5 b会成为double
上面的情形误用会导致错误,比如上面的a本事要初始化为double的情形,会被自动初始化为int导致不符合预期
当这个特性用于复杂类型时候,会显现其威力。可以节省不少脑细胞。
std::vector <double> scores;
auto pv = scores.begin();
此时,pv会被正确的初始化为std::vector<double>::iterator
再举一个例子:
1 #include <iostream>
2.打印进度;
之前一直好奇一些程序的进度是怎么打印的,比如rsync文件过程中的百分比,这些数据不是按行打印的,而是在原地变化,现在终于搞懂这个是怎么搞的了,其实很简单,就是用了转义字符\r 回车符合,其实回车和换行还是有区别的,但是以前都是知其然而不知其所以然。具体可以参考程苓峰的这篇blog:《回车和换行》
代码如下:
1 #include <iostream>
2 #include <unistd.h>
3 #define MAXLINE 10
4 int main(int argc, const char * argv[])
5 {
6 char line[MAXLINE+1] = {};
7 for (int i=0 ;i < MAXLINE ;i++){
8 line[i] = '-';
9 std::cout << "\r" << line << i*10 << "%" ;
10 std::cout.flush();
11 sleep(1);
12 }
13 std::cout << std::endl;
14 return 0;
15 }
3.auto声明(P66)
auto声明可以让编译器根据其初始值的类型来推断变量的类型,auto起源于c语言,但是很少使用
例如:auto a = 100 a会被编译器初始化为int类型
auto b = 1.5 b会成为double
上面的情形误用会导致错误,比如上面的a本事要初始化为double的情形,会被自动初始化为int导致不符合预期
当这个特性用于复杂类型时候,会显现其威力。可以节省不少脑细胞。
std::vector <double> scores;
auto pv = scores.begin();
此时,pv会被正确的初始化为std::vector<double>::iterator
再举一个例子:
1 #include <iostream>
2 #include <unistd.h>
3 using namespace std;
4 int main(int argc, const char * argv[])
5 {
6 char a = 'a';
7 char b = 'b';
8 char c = 'c';
9 char * line[3] = {&a, &b, &c};
10 char ** p_line = line;
11 auto pp_line = line;
12 std::cout << *p_line[1] << std::endl;
13 std::cout << *pp_line[2] << std::endl;
14 return 0;
15 }
在这里,p_line与pp_line是一样的,用auto会省略很多麻烦
注:因此特性在c++11中添加,所以使用此特性编译时需要加参数--std=c++11
4.显示原始字符串(P88)
如果要打印出带有双引号的字符串,一般情况下只能在其中加入转义字符,c++11提供了一种方便的办法,可以直接输出原始字符串。
例如:
15 }
在这里,p_line与pp_line是一样的,用auto会省略很多麻烦
注:因此特性在c++11中添加,所以使用此特性编译时需要加参数--std=c++11
4.显示原始字符串(P88)
如果要打印出带有双引号的字符串,一般情况下只能在其中加入转义字符,c++11提供了一种方便的办法,可以直接输出原始字符串。
例如:
std::cout << R"( hello "world" "\n" .)" << std::endl;
可以直接输出字符串:hello "world" "\n” .
如果要输出的字符串中含有括号,只需在双引号与逗号之间添加任意的基本字符即可:如
std::cout << R"i( hello ( my ) "world" "\n" .)i" << std::endl;
就可以输出:hello (my) "world” "\n"
其中i可以换成除了左右括号以及斜杠之外的任意可见字符
注:因此特性在c++11中添加,所以使用此特性编译时需要加参数--std=c++11
5.程序的变量存储区(P117)
以前对程序的变量存储有过一点接触,但只是听说,看了这个之后,对于程序中变量的存储区域了解的多了一点
a>自动存储(栈)
在程序中定义的常规变量,在函数调用时候产生,函数结束时候消亡被释放,存储于栈中,正好满足栈的特点,先进后出
b>静态存储
待详细了解
c>动态存储(堆)
通过new申请的空间,都是在堆上,他们申请之后除非用户主动释放以及程序结束,其生命周期将一直持续。知道用户用delete释放,或者程序结束。这种机制给予程序员对数据更大的控制权。
可以直接输出字符串:hello "world" "\n” .
如果要输出的字符串中含有括号,只需在双引号与逗号之间添加任意的基本字符即可:如
std::cout << R"i( hello ( my ) "world" "\n" .)i" << std::endl;
就可以输出:hello (my) "world” "\n"
其中i可以换成除了左右括号以及斜杠之外的任意可见字符
注:因此特性在c++11中添加,所以使用此特性编译时需要加参数--std=c++11
5.程序的变量存储区(P117)
以前对程序的变量存储有过一点接触,但只是听说,看了这个之后,对于程序中变量的存储区域了解的多了一点
a>自动存储(栈)
在程序中定义的常规变量,在函数调用时候产生,函数结束时候消亡被释放,存储于栈中,正好满足栈的特点,先进后出
b>静态存储
待详细了解
c>动态存储(堆)
通过new申请的空间,都是在堆上,他们申请之后除非用户主动释放以及程序结束,其生命周期将一直持续。知道用户用delete释放,或者程序结束。这种机制给予程序员对数据更大的控制权。
没有评论:
发表评论