31.继承构造函数
struct B: A{ using A::A; };
32.委派构造函数
class A{ public: A() : A(1234){} //先调用A(int) A(int n1) : A(n1, 'C'){} //先调用A(int, char) A(char c1) : A(2, c1){} //先调用A(int, char) private: A(int n2, char c2) : my_int(n2), my_char(c2){} int my_int; char my_char; }
应用于模版
class A{ public: A(vector<int> &v) : A(v.begin(), v.end()); A(deque<short> &d) : A(d.begin(), d.end()); private: template<class T> A(A n1, T n2) : my_list(n1, n2) {} list(int) my_list; }
捕捉异常
class A{ public: A() try : A(1234) {init();} catch(...) {error();} A(int n) {throw 0;} //构造时执行error(), 而不执行init() }
33.右值引用
- 331.指针成员拷贝构造
class A{ public: A() : my_ptr(new int(1234)) {} A(A ©) : my_ptr(new int(*copy.my_ptr)) {}//新申请一块内存,避免重复析构同一块内存 ~A() {delete my_ptr;} int *my_ptr; }
- 332.移动语义
class A{ public: A() : my_ptr(new int(1234)) {} A(const A& copy) : my_ptr(*copy.my_ptr) {} A(A&& move) : my_ptr(move.my_ptr) {move.my_ptr = nullptr;} ~A() {delete my_ptr;} int* my_ptr; } A GetTmp() { A tmp; return tmp; } int main(){ A one = GetTmp(); }
1.执行
GetTmp()
,创建A1并初始化后返回,
2.创建并初始化A2,即A2(A1)
, 执行的是move
而不是copy,它将A1的指针赋值给A2,并将A1的指针清掉,
3.析构A1
,由于指针清掉了,所以初始化时的内存没有被释放
4.创建并初始化one,即one(A2)
,重复第2步,第3步
5.析构one
,此时内存才真正被释放,它是A1初始化时申请的
- 333.有名字的是左值, 没名字的是右值, 左值
*p=1234
, 右值p=1234
- 334.在
<utility>
中提供了std::move
函数,它将左值强制转化为右值引用
- 335.
swap(T a, T b)
函数使用移动语义进行交换,
移动构造函数不应该写抛出异常,
编译选项-fno-elide-constructors
关闭优化以使用移动/拷贝语义,否则变量直接替换成右值进行编译
36.完美转发
引用折叠规则:typedef int T; typedef T& TR;//or typedef T&& TR TR a;//or TR& a , TR&& a
TR定义为
T&
时,a的类型都是A&
TR定义为T&&
时,TR
/TR&&
的类型为A&&
,TR&的类型为A&
template <typename T, typename U> void PF(T&& t, U& func){ func(std::forward<T>(t)); }
forward()
与move()
功能相同,完美转发能够把引用类型准确传给调用函数
35.显示转换操作符
explicit
class A{} class B(){ public: explicit operator A() const {return A();} } void func(A a){} void main(){ B b; A a1(b);//通过 A a2 = b;//错误 A a3 = static_cast<A>(b);//显式转换,通过 func(b);//错误 }
351.列表初始化, 头文件
<initializer_list>
,声明一个以initialize_list<T>
模版类为参数的构造函数,就能够使自定义类使用列表初始化void func(initializer_list<int> numbers){} int main(){ func({1, 2, 3}); func({}); }
352.使用花括号初始化可以防止类型收窄
const int x = 1234; char a = x;//通过 char b = {x};//错误 char* c = new char(1234);//通过 char* d = new char{1234};//错误
36.POD类型
37.联合体
38.用户自定义字面量
39.内联名字空间
inline namespace space1{ class A{}; } namespace space2{ A a;//A in space1 class A{}; A b;//A in space2; }
310.模版的别名
template<typename T> using NewName = std::map<T, char*>; NewName<int> a;//等同于std::map<int, char*> a;
标签:11,1234,通用,int,C++,char,func,my,ptr From: https://www.cnblogs.com/redraincontrol/p/18315000311.SFINAE规则:特殊场景使用特殊模板版本,另外则是通用模板版本
struct A{ typedef int my_int; }; template <typename T> void func(typename T::my_int) {}//#1 template <typename T> void func(T) {} //#2 int main(){ func<A>(1234);//调用#1,因为存在A::my_int func<int>(1234);//调用#2,因为不存在int::my_int }