C++2.0 新特性

语言

Variadic Templates

move Semantics

auto

Range-base for loop

Initiallizer list

Lambdas

标准库

type_traits

Unordered容器

forward_list

array

tuple

Con-currency

RegEx

C++ Standard演化

  • c++ 98 (1.0)
  • c++ 03 (TR1,Technical Report 1)
  • c++ 11 (2.0)
  • c++ 14

—-Part for Language—-


Spaces in Template Expressions

1
2
vector<list<int> > // OK in each C++ Version
vector<list<int>> // OK since C++11 可以省略空格,编译器不会误以为为>>运算符

nullptr and std::nullptr_t

nullptr关键字

nullptr可以自动转换为每一个指针类型,但不会转换为任何整数类型,其基本类型为std::nullptr_t

c++11使用nullptr来指定指针不指向任何值(void*)

而不是0或者NULL,NULL本质就是0

std::nullptr_t类型

一个基本的数据类型

中定义

auto keyword

可用于类型推断

用于复杂的/太长的类型

Uniform Initialization

一致性初始化 - {}

Simple Test

底层编译遇到{}会形成一个initializer_list

该容器内部关联一个array<T,n>,根据欲创建对象的构造函数的参数选择1 or 2进行初始化

  1. 直接传递initializer_list

  2. 逐个拆解array<T,n>中的元素调用相应的构造函数

    若创建对象内部无initializer_list做参数的构造函数,则必须要求{}与其已有构造函数的参数一致

1
2
3
4
5
6
7
8
//变量名后直接加{}进行初始化

//构造函数调用次数?
int values[] {1,2,3};
//使用方式1
vector<int> v {2,3,4,5,6};
//使用方式2
complex<double> a {4.0,5.0}

注意:

  • 如果使用{空}初始化,即使是局部变量也会强制具有初始值 0 or nullptr or …
  • 使用一致性初始化时候不允许隐式收缩转换(高精度->低精度),反过来允许
  • 若有意进行收缩转换,则应使用静态强制转换static_cast(high_type_data)

initializer_list

Inner Construct

内部并不是复合(has)一个array容器,而是存放一个指向array元素的迭代器

浅拷贝

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
template<class T>
class initializer_list {
public:

typedef T value_type;
//指向常量的指针说明initializer_list不具备对赋予数据的写的功能
typedef const value_type* iterator;
typedef const value_type* const_iterator;
typedef size_t size_type;

constexpr initializer_list():array(0),len(0){}

constexpr const_iterator begin()const noexcept {
return array;
}
constexpr const_iterator end()const noexcept {
return array + len;
}
constexpr size_type size()const noexcept {
return len;
}

private:
//这里私有的构造函数编译器可调用且一定会调用
constexpr initializer_list(const_iterator a,size_type l):array(a),len(l){}
iterator array;
size_type len;
};

In Container

c++11下每个容器都提供了使用initializer_list类型参数的函数重载

  • 构造函数
  • operator=(initializer_list _l)
  • insert(iterator _p,initializer_list _l)
  • assign(initializer_list _l)

In Algorithm

可以使算法可接受不定参数但是类型相同的参数,使用Initializer List对象({})传入参数

print

实现输出多个相同类型参数

1
2
3
4
5
6
7
8
9
//c++11提供initializer_list<>类模板,供用户自定义对象
void print(initializer_list<int> a) {
for (auto p = a.begin(); p != a.end(); p++) {
cout << *p << endl;
}
}
//必须用{}或者initializer_list<>类对象初始化
print({1,2,3,4,5});

max

实现求多个相同类型参数的最大值

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
class Compare {
public:
template<class iterator>
bool operator()(iterator t1, iterator t2) {
return *t1 < *t2;
}
};

//辅助接口函数,用于生成临时functor对象
Compare compare() {
return Compare();
}

//逐个取initializer_list容器关联array容器中个元素采用擂台比较,返回指向最大元素的迭代器
template<class iterator, class Comparee>
iterator ___maxx(iterator first, iterator last, Comparee cmp) {
if (first == last) {
return first;
}

iterator result = first;
while (first != last) {
if (cmp(result, first)) {
result = first;
}
first++;
}

return result;
}

//为___maxx提供functor比较规则
template<class iterator>
iterator _maxx(iterator first, iterator last) {
return ___maxx(first, last, compare());
}

template<class T>
T maxx(initializer_list<T> list) {
return *_maxx(list.begin(), list.end());
}

//调用

maxx({1,2,3,4,5}); //return 5

explict

For ctors taking one augument

explict不允许该类构造函数用于隐式类型转换

只需要提供单一实参的构造函数

eg:带默认参数的构造函数

For ctors taking more than one augument

c++11中也不允许本类构造函数用于隐式类型转换

1
2
//P类中无带initializer_list参数类型的构造函数
P p5 = {77,5,6}; //error:不允许调用explict构造函数用于隐式类型转换

Range-based for statement

只读遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//只读
for ( decl : coll) {
statement
}

//等价于
for(auto p = coll.begin();p!=coll.end();p++) {
//coll.begin() 等价于 begin(coll)
decl = *p;
statement
}

//eg:
//const auto& 只读且更快
for(const auto&elem : coll) {
cout << elem << endl;
}
for(auto& p = coll.begin();p!=coll.end();p++) {
const auto& elem = *p;
cout << elem << endl;
}

读写遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//可读可写
for ( decl& : coll) {
statement
}
//等价于
for(auto p = coll.begin();p!=coll.end();p++) {
//coll.begin() 等价于 begin(coll)
decl& = *p;
statement
}

//eg:
for(auto& elem : coll) {
elem += 3;
}
for(auto& p = coll.begin();p!=coll.end();p++) {
auto& elem = *p;
elem += 3;
}

=default,=delete

一般作用于Big-Three

  • 构造函数
  • 拷贝构造
  • 移动构造
  • 拷贝赋值
  • 移动赋值
  • 析构函数

= default

若用户自定义了任何一个构造函数,则不再使用默认构造函数,若仍需要使用则需要使用= default指出

用与默认构造函数和默认析构函数,表明仍使用该默认版本

用于Big-five之外无意义

1
2
3
4
5
6
class Foo{
Foo(int a):x(a){}
Foo() = default;
private:
int x;
};

= delete

可用于任何函数,表明该函数不能再被调用

No-Copy and Private-Copy

通过= default与= delete与访问权限修饰符构造具有特殊性质的类

No-Copy

不允许被copy

1
2
3
4
5
6
7
struct NoCopy {
public:
NoCopy() = default;
NoCopy(const NoCopy&) = delete; // no-copy
NoCopy& operator=(const NoCopy&) = delete; // no-assignment
~NoCopy() = default;
};

NoDtor

不允许被删除

1
2
3
4
5
6
7
8
9
struct NoDtor {
public:
NoDtor() = default;
~NoDtor() = delete;
//后果自负,该内存无法被清除
};
NoDtor p; //error
auto p* = new NoDtor();
delete p; //error

Private-Copy

不语允许普通对象copy,只允许inner member or friends 调用copy

1
2
3
4
5
6
7
8
struct PrivateCopy {
private:
PrivateCopy(const PrivateCopy&) = default;
PrivateCopy& operator=(const PrivateCopy&) = default;
public:
PrivateCopy() = default;
~PrivateCopy() = default;
};

Alias Template

using

创建类模板的别名Alias,此时Alias也是一个类模板

1
2
3
4
5
6
template<class T>
//声明使用模板
using Vec = std::vector<T,MyAlloc<T>>

//使用别名时无模板
// Vec<int> coll == std::vecor<int,MyAlloc<T>> coll

Single case

要求实现一个test接口,要求只传入容器模板和数据类型来测试该容器的一些特性

测试:test(list,string)通过

难点: 接口如何获得容器的类型和其数据类型

Simple function

1
2
3
4
5
6
7
8
9
10
void test(const Container& c,const Type& a) {
Container<Type> c;
for(int i = 0;i < 100;i++) {
c.insert(c.end(),Type());
}
}
//调用方式
test(list(),string());

//此方式无法通过参数对象获得对象类型

Template function

1
2
3
4
5
6
7
8
9
10
11
12
13
template<class Container,class Type>
void test(const Container& c,const Type& a) {
Container<Type> c;
for(int i = 0;i < 100;i++) {
c.insert(c.end(),Type());
}
}
//调用方式
test(list(),string());

//编译器无法判断Container是类模板
//typename Container<Type> c; ?
//typename用于判断后面子句含有::的类型,该语法不通过

iterator_traits + Template function

1
2
3
4
5
6
7
8
9
10
11
template<class Container>
void test(const Container& c) {
typedef typename iterator_traits<typename Container::iterator>::value_type Type;
for(int i = 0;i < 100;i++) {
c.insert(c.end(),Type());
}
}
//调用方式
test(list());

//可以,但是接口弹性小,使用不方便

Template template parameter + class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template<class T,
template<class T>
Container
>
class test {
public:
typedef T Type;
//创建对象时通过构造函数去测试容器的相关特性
test(){
for(int i = 0;i < 100;i++) {
c.insert(c.end(),Type());
}
}
private:
Container<T> c;
};

//调用方式
test<string,vector>;
//报错原因是vector的第二个alloc模板参数在用作模板模板参数时不会自动使用默认值,需要调用时自行指定第二个模板参数

Template template parameter + class + alias Template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//using
template<class T>
using Vector = std::vector<T,MyAlloc<T>>

template<class T,
template<class T>
Container
>
class test {
public:
typedef T Type;
//创建对象时通过构造函数去测试容器的相关特性
test(){
for(int i = 0;i < 100;i++) {
c.insert(c.end(),Type());
}
}
private:
Container<T> c;
};

//调用方式
test<string,Vector>;
//此时Vector模板虽然只接受一个类型参数,但是却可以同时使用该参数指定第二个alloc模板参数

Template template parameter

模板做另一个模板的参数,一般用于上述情况

Type Alias

using

等同于typedef

1
2
3
typedef T value_type;
using value_type = T;
//无区别,新语法

noexcept

指明某函数不会丢出异常

特别是vector的移动构造函数若不指明noexcept则在grow时不会调用移动构造

growable containers

  • vector
  • deque

Testing

1
2
3
4
5
void swap() noexcept(true) 
{
//甚至可以指定不会丢出异常的条件
//若在swqp出现了异常却未被处理,会将该异常不断往调用点回抛,最终抛向std::terminate(),调用std::abort()终止程序
}

override

用于重写父类的虚函数时向编译器指明重写虚函数的意图

若出现错误导致操作不再是重写操作则报错

final

用于类表明该类不允许被继承

用于虚函数表明该虚函数不允许被重写

1
2
3
4
struct a final{
virtual void b() final{}
};
//注意final的位置

decltype

获取一个表达式的类型

Used to declare return types

用于返回类型复杂未知时

注意:-> decltype(…) 必须绑定 auto 类型说明符

1
2
3
4
5
6
7
8
9
10
template<class T1,class T2>
decltype(x+y) add(T1 x,T2 y) {
//...
}
//此时decltype()使用了作用域之外的对象,报错

template<class T1,class T2>
auto add(T1 x,T2 y) -> decltype(x+y) {
//...
}

In metaprogramming

用于模板

1
2
3
4
5
6
template<class T>
void a(const T& obj) {
typedef T type;
//等价于
typedef decltype(obj) type;
}

Used to pass the type of a lambda

获取lambda对象的类型

1
2
3
4
auto compare = [](...){...};

//<>中传递类型后还必须将lambdas对象传给构造函数才能创建好set对象
std::set<Obj,decltype(compare)> coll(compare);

Lambdas

可理解为-匿名函数对象/匿名functor对象

functor的创建会先有模板类functor类型的声明再去创建functor对象

而Lambdas自定义起便是一个匿名的functor对象,虽然具有functor对象的一些性质,但是

Defination

  1. 捕获外部作用域中访问lambdas的对象

    [=] : 按值传递方式捕获外部作用域中的所有对象

    [&] : 按按引用传递方式捕获外部作用域中的所有对象

    [x,&y] : 捕获指定对象,x按值传递捕获,y按引用传递捕获

  2. 函数参数

    若无参可省略(),若含可选参数项必须含有()

  3. 可选参数项

    • mutable

      若1处的对象按值传递,则若想更改值传递对象的值,必须使用mutable修饰,否则不允许更改

      若1处的对象按引用传递,则可省略,且对对象的更改会影响到外部对象

    • noexcept

    • decltype

      若函数有返回值,则需要通过decltype指定返回值类型,可省略

  4. statement

    可有返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[1](function_arguments) mutable noexcept -> decltype(function_return_statement) {
//statement
};

//调用1
[1](function_arguments) mutable noexcept -> decltype(function_return_statement) {
//statement
}(function_arguments);

//调用2
auto x = [1](function_arguments) mutable noexcept -> decltype(function_return_statement) {
//statement
};

x(function_arguments);

What compiler generates for lambdas ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int tobefound = 5;
auto lambdas1 = [tobefound](int val) {
return tobefound == val;
};

//编译器处理为
int tobefound = 5;

class UnNamedFunctor {
public:
UnNamedFunctor(int x):tobefound(x){}

auto operator()(int val) -> decltype(tobefound == val) {
return tobefound == val;
}
private:
int tobefound;
};

UnNamedFunctor lambdas2(tobefound);

注意:

  1. 虽然编译器会将lambdas当做匿名functor处理,但是由于其特殊语法,所以lambdas并无默认构造函数与对=运算符的重载

    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

    2. 使用到lambdas传参时(如创建关联式容器)不仅需要在<>传递lambdas对象类型,还需要将lambdas对象传递给容器构造函数进而创建容器

    因为容器存在通过传入类型的默认构造函数创建对应类型对象的默认构造函数,而lambdas无默认构造函数,报错



    # Variadic Templates

    可变模板参数

    可随**使用方式**而动态的**拆分**可变参数包

    可用于递归,但Variadic Templates**不会产生递归**,而是Variadic Templates可动态拆分的特性**可用于递归**

    ## In function template

    递归调用

    处理参数

    ### Print

    ```c++
    template<class T,class... Types>
    //指定拆分方式为n = 1 + (n - 1) / n = a + args...
    void print(const T& a, const Types&... args) {
    cout << a << endl;
    //sizeof...(args) 可返回可变参数的个数
    cout << "剩余可变参数个数: " << sizeof...(args) << endl;
    //使用可变参数性质进行递归调用
    print(args...);
    }

    //若本函数模板与上面的函数模板并存,则只会调用上面更特化的版本
    template<class... Types>
    void print(const Types&... args) {
    //...
    }

    //设置递归终止时的处理方式
    //按照指定方式(1,n-1)一直进行拆分,处理base_case(n-1=0)递归结束的情况
    void print() {}

    int main()
    {
    print("abc", 123, 465);
    }

Hash Function

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
#include<functional> //引入相应的头文件

class CustomerHash {
std::size_t operator()(const Customer& c) const {
return hash_val(c.first, c.second, c.third);
}
};

//计算hashcode的函数模板
template<class T>
void hash_combine(std::size_t& seed, const T& val) {
seed ^= std::hash<T>()(val) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

//辅助接口函数,虽然接受可变参数,但是未指定拆分方式,不进行拆分,不用于递归,用于返回hash值
template<class... Types>
std::size_t hash_val(const Types&... args) {
std::size_t seed = 0;
hash_val(seed, args...);
return seed;
}

//指定拆分方式为n = 1 + (n - 1),进行递归调用逐个取可变参数中的首元素更新seed
template<class T, class... Types>
void hash_val(std::size_t& seed, const T& val, const Types&... args) {
hash_combine(seed, val);
hash_val(seed, args...);
}

//处理递归结束的情况
template<class T>
void hash_val(std::size_t& seed, const T& val) {
hash_combine(seed, val);
}

printf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void printf(const char* a) {
while (*a) {
if (*a == '%' && *(++a) != '%') {
throw std::runtime_error("invalid format string:missing arguments");
cout << *a++;
}
}
}

template<class T, class...Types>
void printf(const char* a,const T& x, const Types&... args) {
while (*a) {
if (*a == '%' && *(++a) != '%') {
cout << x << " ";
printf(++a,args...);
return;
}
std::cout << *a++;
}
throw std::logic_error("extra argument!");
}

//调用
printf("%d%s\n", 5, "hello variadic templates");

max

1
2
3
4
5
6
7
8
9
int maximum(int n) {
return n;
}

template<class... Types>
int maximum(int n,const Types&... x) {
//调用标准库的max函数动态拆解可变参数并作递归比较得到最大值
return std::max(n, maximum(x...));
}

In class template

递归继承,复合

处理类型

Recursive inheritance

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
//tuple
//通过可变参数的可动态拆分特性递归实现继承体系
template<class Head,class... Tail>
class tuple<Head,Tail...> : private tuple<Tail...> {
public:
typedef tuple<Tail...> inherited;

tuple() {}
tuple(const Head& a,const Tail&... args):m_head(a),inherited(args...){}

//返回tuple对象的head元素
Head head() {
return m_head;
}

//通过上转型为父类类型截断本类数据
//返回不含m_head的含tail部分的tuple对象
inherited& tail() {
return *this;
}
protected:
Head m_head;
};

//当递归至父类为tuple<>时作停止递归的处理
template<>
class tuple<> {};

Recursive Composition

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
//tup
//通过可变参数的可动态拆分特性递归实现复合体系
template<class Head,class... Tail>
class tup<Head,Tail...> {
public:
typedef tup<Tail...> composited;

tup() {}
tup(const Head& a,const Tail&... args):m_head(a),m_tail(args...){}

//返回tup对象的head元素
Head head() {
return m_head;
}

//返回复合的
composited& tail() {
return m_tail;
}
protected:
Head m_head;
composited m_tail;
};

//递归终止处理
template<>
class tup<> {};

—-Part for STL—-


Move Semantics

Rvalue References

一种引用类型,该引用类型可以避免不必要的copy操作

当 = 的右侧为Rvalue References类型时,左值对象可以偷取右值对象的内容而不必额外分配内存,执行copy操作,而是执行movecopy操作

Rvalue and Lvalue

Rvalue

只能出现在 = 右侧的对象

临时对象为右值对象

Lvalue

可以出现在 = 左侧的对象

注意:c++标准库中很多类的运算符重载导致该规范被打破,但是大部分情况仍是该规范主导

Transition

可以通过标准库中的std::move(Lvalue_obj)将Lvalue_obj转换为右值对象

1
2
3
4
template<class _Tp>
constexpr typename std::remove_reference<_Tp>::type&& move(_Tp&& t) noexcept {
return static_cast<typename std::remove_reference<_Tp>::type&&>(t);
}

Perfect Forwarding

Unperfect Forwarding

对象在传递过程中无类型保证措施,无法确保对象的透明转发

右值引用对象会由于某些原因(如被重新封装为named object)而转换为左值引用对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1
void process(int& i) {}
//2
void process(int&& i) {}

void forward(int&& i) {
process(i);
}

//调用
process(1); //调用1
int a = 1;
process(a); //调用2

forward(1); //发现转发过程调用了2而非1,因为forward内部将1封装成了named object,从而转换为了一个左值对象
forward(std::move(a)); //发现转发过程调用了2而非1

Perfect Forwarding

通过一个forward函数模板来保证任意参数的透明转发,即各参数性质不会发生改变

静态强制转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>//std::forward<Lvalue_type>()

>//forward lvalue
>template<class _Tp>
>constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type& t) noexcept {
return static_cast<_Tp&&>(t);
>}

>//forward rvalue
>//就算被封装成了obj也要萃取出obj中的右值引用类型
>template<class _Tp>
>constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type&& t) noexcept {
static_assert(!std::is_lvalue_reference<_Tp>::value,"_Tp is an lvalue reference type");
return static_cast<_Tp&&>(t);
>}

>template<class Lvalue_type,class Rvalue_type>
>void funA(const Lvalue_type& a,Rvalue_type&& b) {
_forward( std::forward<Lvalue_type>(a),std::forward<Rvalue_type>(b) ) {}
>}

Move-avare class

针对于Pointer Like Class而言

因为movecopy一定经过一次浅拷贝,即一字节一字节的赋值,若类中无指针成员,则movecopy效率几乎等同于copy

Container of elements is move-able

容器在执行元素copy操作时,仍触发容器的copyconstruct-cctor,但是触发了元素的movecopy-MAsgn

元素类型内部对move进行了实现

move-able elements 对vector的操作效率,deque非首尾插入元素时影响最大,对其结点构成的容器影响不大

也就是说move-able elements 优化了容器的cctor

Defination

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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
class MyString {
public:
//静态成员用于计数各类型函数的执行次数
static size_t CCtor;
static size_t MCtor;
static size_t CAsgn;
static size_t MAsgn;
static size_t Ctor;
static size_t Mtor;
static size_t Dtor;

MyString() :data(nullptr), len(0) {
++Dtor;
}
MyString(const char* x) :len(strlen(x)) {
++Ctor;
_copy(x);
}
MyString(const MyString& x) {
++CCtor;
_copy(x.data);
}
//moveable的函数必须有noexcept关键字修饰否则不会调用,注意位置
MyString(MyString&& x) noexcept :data(x.data), len(x.len){
++MCtor;
//偷取后需要切断原对象对该内存的连接
//重要性:
//若没及时切断连接,两个指针同时指向一个内存,若传入右值引用对象(匿名对象)生命周期提早结束,会将该共享内存清除,导致本对象无法使用
x.data = NULL;
x.len = 0;
}
MyString& operator= (const MyString&x) {
++CAsgn;
if (this == &x) {}
else {
if (data) delete data;
len = x.len;
_copy(x.data);
}
return *this;
}
//返回值仍为引用,因为仅根据右值引用产生不同的赋值操作但是返回类型都是一样的
MyString& operator= (MyString&& x) {
++MAsgn;
//先进行判断是否为self赋值
if (this == &x) {}
else {
//所有赋值必须先清理原内存后再进行赋值
if (data) delete data;
//偷取内容
len = x.len;
data = x.data;
//切断连接
x.data = NULL;
x.len = 0;
}
return *this;
}
~MyString() {
++Dtor;
if (data) {
delete data;
}
}

private:
char *data;
int len;
//封装内部工具函数用于copy即开辟空间逐个赋值
void _copy(const char* x) {
data = new char[len + 1];
memcpy(data, x, len);
data[len] = '\0';
}
};

size_t MyString::CCtor = 0;
size_t MyString::MCtor = 0;
size_t MyString::CAsgn = 0;
size_t MyString::MAsgn = 0;
size_t MyString::Ctor = 0;
size_t MyString::Mtor = 0;
size_t MyString::Dtor = 0;

Interface

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
#include<ctime>

//测试部分
template<class T>
void output_static_data(const T& mystr) {
cout << typeid(mystr).name() << "--" << endl;
cout << "CCtor = " << T::CCtor
<< "MCtor = " << T::MCtor
<< "CAsgn = " << T::CAsgn
<< "MAsgn = " << T::MAsgn
<< "Ctor = " << T::Ctor
<< "Mtor = " << T::Mtor
<< "Dtor = " << T::Dtor
<< endl;
}

template<class M>
void test_moveable(M c, long& value) {
typedef typename iterator_traits< typename M::iterator >::value_type Type;
char random[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++) {
snprintf(random, 10, "%d", random());
auto ite = c.end();
//测试move_able elements对容器插入效率的影响
//Type()为临时对象,所以传递的为右值引用对象
c.insert(ite, Type(random));
}
cout << "milli_seconds : " << clock() - timeStart << endl;
cout << "size() = " << c.size() << endl;
output_static_data(*(c.begin()));
}

Container is move-able

1
2
3
4
5
6
7
8
//G4.9 vector
//拷贝构造
vector(const vector& __x):_Base(__x.size(),_Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())) {
this->_M_impl.M_finish = std::__uninitialized_copy_a(__x.begin,__x.end(),this->_M_impl._M_start,
_M_get_Tp_allocator())
}

//右值拷贝构造

Array

数组

组成

内含一个数组成员

迭代器 native pointer

无构造函数析构函数

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
//TR1
#pragma once
#include <array>
template <typename _Tp,std::size_t _Nm>
struct Array {

typedef _Tp value_type;
typedef _Tp* pointer;
typedef value_type* iterator;

public:

//Array无构造函数析构函数

iterator begin() {
return &arr[0];
}

iterator end() {
return &arr[_Nm];
}

private:
value_type arr[_Nm ? _Nm : 1]; //若数组长度参数为0默认将长度值为1
};

Hashtable

G4.9

vector + 链表

hash-function

通过对hash类模板 functor 的特化完成不同基本数据类型的hash_code的计算

1
2
3
4
5
6
7
8
9
10
11
12
template<class T>
struct hash{};

//eg:
//__hash_base<size_t,size_t>相当于unary_function 为了使特化版本adaptable
template<>
struct hash<int> : __hash_base<size_t,size_t> {
size_t operator()(int x) {
return x;
}
}
hash<int>()(1); //return 1

Tuple

元组 不同数据类型数据的组合

Interface testing

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
//tuple对象的创建
tuple<string, int, int> t("123",10,11);
auto t2 = make_tuple("123");

//对象成员的获取
//get<num>(tuple_obj) num为从0开始的序号索引
int i = get<1>(t);
int a, b;
string c;

//tie(args...) = tuple_obj 元素绑定
//实现用args参数"绑定"tuple中的元素 赋值性的绑定 即绑定后值变化互不影响
tie(c, a, b) = t;
//eg:
get<0>(t) = "5";
cout << c << endl;
//结果仍为123

//stl中tuple对运算符的重载
//t < t2
//t = t2;

//获取tuple中元素个数
typedef tuple<string, int, int TupleType
cout << tuple_size<TupleType>::value << endl;

//获取某个元素的类型
//...


//获取tuple的head元素
string s = t.head(); // s="123"
//获取tuple的tail部分tuple对象
auto tail = t.tail(); // tail = tuple<int, int> t(10,11)
//获取tail的head元素
int se = tail.head();
//值得注意的是head(),tail()在c++17中不再使用该名称

Internal structure - G4.8

通过可变类型参数可动态拆分特性而构建的一个继承体系结构

即每一个数据类型的数据单独封装为一个类

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
//tuple对象的创建
tuple<int, float, string> t(41,6.3,"nico");

//tuple
//通过可变参数的可动态拆分特性递归实现继承体系
template<class Head,class... Tail>
class tuple<Head,Tail...> : private tuple<Tail...> {
public:
typedef tuple<Tail...> inherited;

tuple() {}
tuple(const Head& a,const Tail&... args):m_head(a),inherited(args...){}

//返回tuple对象的head元素
Head head() {
return m_head;
}

//通过上转型为父类类型截断本类数据
//返回不含m_head的含tail部分的tuple对象
inherited& tail() {
return *this;
}
protected:
Head m_head;
};

//当递归至父类为tuple<>时作停止递归的处理
template<>
class tuple<> {};

继承图示

image-20210712164552782