精读C++ primer
从今以后,精读primer遇到漏洞或者新知识在这里记录下来~
1.C++11后,可以进行列表初始化赋值例如:
int a=0; int a(10); int a={0}; int a{0};后2中属于列表初始化,但是遇到内置类型的变量,不能使用列表初始化,不然会报错
4.C++里面的const 对象默认仅在文件内有效
5.int a=1; int *p1=&a; const int b=2; const int *p2=&b;
6.使用auto也能在一条语句中声明多个变量.因为一条声明语句只能有一个基本数据类型.例如
auto i=0, *p=&i; //正确
auto i=0, p=3.14;//错误,i与p类型不一样
其中包括不能一个变量是int,另外一个是const int
比如:int a=1; const int b=2;
7.auto会忽略掉顶层const,但是底层const会保存下来例如:
int a=1; const int b= 2;
auto c=b;//c是一个整形而不是常量整形
auto c=&a;//c是一个整形指针
auto c=&b;//c是一个指向整形常量的指针(对常量对象取地址是一种底层const)
如果希望推断出的auto类型是一个顶层const,需要明确指出:
int a=1;
8.使用decltype注意一点,如果获得的是引用类型,那么必须初始化例:
const int a=1, &b=a;
decltype(b) c;//错误,c是一个引用,必须初始化
int a=1 ,*p=&i;//这里的decltype(*p)有点特殊,具体原因见primer63
decltype(*p) b;//错误 ,b是int &,必须初始化
//decltype的表达式如果是加上了括号的变量,结果将是引用
int i=1;
decltype ((i)) d; //错误,d是int&,必须初始化
decltype (i) e;//正确,e是一个(未初始化的)int
如果想使decltype(x)引用类型不初始化,那么可用decltype(x+0)转化成一个int,而非int&
9.因为历史原因和为了与C兼容,C++语言中的字符串字面值不是标准库string的对象即 "hello" 和string s="hello"不是同一个类型
而且,加法运算符两侧至少有一个是string对象
string a="hello";
string b=a+","+"world;//正确,a+","先结合形成string对象,再和world形成 string对象
string b= "hello"+","+a;//错误, "hello"+","是两个字符串字面值,不能相加赋值给string 对象
10.int arr[10];
int (*p)[10]=&arr; //&arr是一个数组指针,指向int [10]的数组,所以要用数组指针接纳
int (&p)[10]=arr; //p引用一个含有10个整数的数组
而且修饰符的数量没有限制
int *(&p)[10]=arr;
11.比较C风格字符串时,不能直接比较,因为比较的指针而不是字符串本身,但是可能2个指针
指针向的并非同一对象,所以将得到未定义的错误,需要调用strcmp函数,C++字符串则可以直接比较
谨记:2个指针的减法有意义,2个指针的加法没意义
12.可以使用数组来初始化vector对象.要实现这一目的,拷贝区域的首地址和尾后地址就可以了.
int arr[] = { 1,2,3,4,5,6 };
vector<int>v(begin(arr),end(arr));
当然也初始化vector对象也可能是数组的一部分.
int arr[] = { 1,2,3,4,5,6 };
vector<int>v(arr+1,arr+4);
13.要使用范围for语句处理***数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型
具体见primer114
14 .int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
for (auto p = a; p !=a+3; p++)
{
for (auto q = *p; q != *p + 4; ++q)
{
cout << *q << " ";
}
cout << endl;
}
也能遍历数组,p是一个数组指针,指向了含有4个整数的数组,q是指向一个整数数组的首元素.
那么*q的含义就和int a[]={3,4,5},int b=*a;这个*a的含义一样,属于解引用,所以能遍历数组
15.size_t是cstddef头文件中定义的一个与机器实现有关的无符号整形类型,它的空间足够大,能够表示任意数组的大小
size_type是string和vector定义的类型的名字,能存放下任意string对象或vector对象的大小.在标准库中,size_type被定义无符号类型
16.int a[3][4] = { 3,4,5,6,7,8,9,10,11,12,13,14 };
int(&p)[4] = a[0];//把p定义成一个含有4个整数的数组的引用,然后将其绑定到a的第1行
17.const_cast可以改变对象底层const(只有这个可以),但是有可能产生未定义的行为.如果对象本身是一个非常量,强制转换后获得写权限是合法的,
但是如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果.例如:
这样是没有问题的:
const int *p2; int a = 2;
p2 = &a;
int *p = const_cast<int*>(p2);
*p = 3;
cout << a;
输出是3.但是把int a改成 const int a=2;就是未定义了
18.initializer_list是可变参数模板,是一直标准库模型,例如:
void error_msg(initializer_list<string> il)
{
for (auto beg = il.begin(); beg!=il.end(); beg++)
{
cout << *beg << " ";
}
cout << endl;
}
int main()
{
int a = 0;
if (a == 0)
{
error_msg({ "a","b","c" });
}
else
{
error_msg({ "a","b"});
}
return 0;
}
19.函数调用返回类型是引用的话得到是左值,其他返回类型得到右值.我们可以像使用其他左值那样来使用返回引用的函数的调用,特别是,我们能为返回类型是非常量引用的函数的结果赋值:(注意是非常量)
20.C++11新标准规定,函数可以返回花括号包围的值的列表,此时的列表页用来对表示函数返回的临时量进行初始化
21.,返回一个值的方式和初始化一个变量或形参的方式完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果,记住,一般都会拷贝一个副本返回,但是如果返回的是引用的话,那么就不会拷贝副本,返回的是一个别名.什么情况下返回的引用会无效呢? 如果引用所引用的是函数开始之前就已经存在的对象,那么返回的引用是有效的,如果是引用的函数的局部变量,函数结束时候就失效了,此时返回的引用无效.当不希望返回的对象被修改时,返回对常量的引用
22.C++新语法糖:使用尾置类型返回
//返回指向数组的指针
auto func1(int arr[][3], int n) -> int(*)[3] { return &arr[n]; }
这段代码非常符合尾置返回类型设计的用途,按照以往的方式我们可能需要:
C++
看书的时候认真点(前提是选对书),这问题就应该直到答案,
或者多动动脑,思考一下应该也能知道,说说我的观点:
只能用于类的一般成员函数,而不能用于静态成员函数。
静态成员函数有什么不同?根本上说,静态成员函数里面没有this指针,
就是说,相当于一个定义于该类内部的普通(非成员)函数,
这也是为什么静态成员函数不能访问成员变量的原因,
所以,静态成员函数根本不存才“改变this指向的内容”这个概念,
结论(at last):const这个修饰符,用于静态成员函数没有意义。