Cpp的一些知识点

C++模板的偏特化与全特化

引用:http://harttle.com/2015/10/03/cpp-template.html

特化就是把原始模板中的部分(偏特化)或全部(全特化)模板参数固定下来,定制特定参数的实现。
注意函数模板只能全特化,要得到偏特化的效果可以通过函数重载的方式。
在实例化的时候,会去匹配最接近实例参数的模板实现。
std命名空间不允许添加任何内容。

简单实现:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>

// 原始模板
template<typename T1,typename T2>
class Test {
T1 t1;
T2 t2;
public:
void print() {
std::cout<<"aaa"<<std::endl;
}
};

// 偏特化
template<typename T2>
class Test<int,T2> {
int t1;
T2 t2;
public:
void show(T2 t) {
std::cout<<t<<std::endl;
}
};

// 全特化
template<>
class Test<char,char> {
public:
void go(char c) {
std::cout<<c<<std::endl;
}
};

// 原始模板
template<typename T1,typename T2>
T1 func(T1 t1,T2 t2) {
return t1;
}

// 全特化
template<>
int func<int,int>(int t1,int t2) {
return t1+t2;
}

int main()
{
Test<double,double> Tdouble;
Test<int,int> Tint;
Test<char,char> Tchar;
Tdouble.print();
Tint.show(5);
Tchar.go('A');

std::cout<<func<double,char>(3.14,'a')<<std::endl;
std::cout<<func<int,int>(5,10)<<std::endl;
return 0;
}

输入结果:

aaa
5
A
3.14
15


C++内部类

内部类就是定义在一个类内部的类。
C++的内部类没有外部类的this指针,所以不能访问外部类的非静态成员,
只能访问外部类的静态成员和枚举。


C++ 逗号表达式

逗号表达式的计算顺序是从左到右的,
表达式的值为最后一个式子的值。
如:

1
2
int a,b,c;
int d=(a=1,b=a+2,c=b+3);

输出:d==6


do{…}while(0)

在linux 内核和很多库中会看到这样的用法。其意义在于:

  1. 用于宏定义,保证这个宏定义在任何环境下的展开都能得到预期的形式。
  2. 代替goto的使用。
  3. 为跨平台定义空宏,避免警告。
  4. 定义单一代码块执行复杂操作,避免命名冲突。
    以上如果不理解的,参考:http://www.cnblogs.com/lanxuezaipiao/p/3535674.html

vector

  • at 和 []
    一个是函数一个是操作符。at提供边界检查,越界时会抛出异常,[]会向原生数组一样去访问。
    例如:
    vector vec={0,1,2,3};
    vec.pop_back();
    vec[3]; //输出3
    vec.at(3); // 异常

  • max_size
    vector能拥有的最大size,考虑了重新分配,比capcity大很多。

  • size 与capacity
    capacity只会增长,不会变小,而size会。
    通常用pop_back,clear等方法删除元素,首先会通过萃取判断是否要执行析构,然后改变size的大小,不清空内存。

  • resize 和 reserve
    resize改变size的大小,如果是增大,则同时看capacity是否需要增大,并调用默认构造函数,如果是减小,析构(如果需要)然后减小size。
    reserve改变capacity的大小,如果是增大capacity,则改变capacity的大小,如果是减小,则不变,这个过程size 不变,也没有任何元素的构造。


static数据的初始化

  • C里面:
    global和static差不多。
    在编译的时候确定。如果有初始值存在data段;没有初始值存在bss段,在装载时初始化为默认值。

  • C++里面:
    分为静态初始化和动态初始化。静态初始化是那些不需要调用函数的变量,在编译时就能确定的;动态初始化是那些要调用函数的,需要运行期确定。
    C的那一部分不变,在编译时就确定了。
    对象的部分,包括static和global的,还是一些需要调用函数的,由于编译期无法确定值,全都存在bss段,在运行期main函数执行前,调用构造函数初始化。同一编译模块的对象初始化顺序按照定义的顺序,不同模块之间的顺序无法确定。在链接时,各个模块的bss段整合成一个bss段,但顺序不确定,这造成了各个模块之间的顺序是不确定的,所以在模块之间引用全局对象会造成未定义行为。
    解决方案是把全局对象的构造放到函数里面,因为C++里的局部静态对象的初始化是在第一次调用的时候(在对象之前的一点空间标记是否初始化),这可以避免引用为初始化的对象,这一点也是C++和C对于具备静态对象的初始化区别。