Libstdc++ 初窥

写了两周stdlibc++.纪录点对c++的理解吧.

default constructor

  1. constructor 是不能被定义在class外的
  2. 当constructor被定义为default, compiler 会生成一个implicity declared constructor, calls the default constructors of the bases and of the non-static members of this class.

copy constructors

  1. 当user没有定义copy ctor的时候, compiler 会生成一个implicity declared的版本.
  2. 这个implicity的版本在一定情况下会被delete,详情见cppreference.

SFINAE

Substitution failure is not an error - 编译器不会立刻炸,会搜索next

类型擦除(把原来的类型去掉,换成统一类型,换言之cast)

1
2
3
4
char a[10];
void* ap = (void*)a;
int b;
void* bp = (void*)&b;

这里就都cast成了void指针。

再来看个Any的例子:

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
class Any {
public:
  Any() : ptr(nullptr) {}

  Any(const Any& other) {
      ptr = other.ptr->Copy();
  }

  Any& operator=(const Any& other) {
      this->~Any();
      ptr = other.ptr->Copy();
      return *this;
  }

  ~Any() {
      if (ptr != nullptr) {
    delete ptr;
      }
  }

  template<typename T>
    void Assign(const T& data) {
  this->~Any();
  ptr = new Wrapper<T>(data);
    }

  template<typename T>
    T* Get() {
  auto wrapper = dynamic_cast<Wrapper<T>*>(ptr);
  if (wrapper != nullptr) {
      return &wrapper->data;
  }
  return nullptr;
    }

private:
  struct AnyData {
      virtual ~AnyData() { }

      virtual AnyData* Copy() = 0;
  };

  template<typename T>
    struct Wrapper : public AnyData {
  Wrapper(const T& data) : data(data) {}

  AnyData* Copy() override {
      return new Wrapper<T>(data);
  }

  T data;
    };

  AnyData* ptr;
};

#include <iostream>

int main() {
    Any a;
    a.Assign<int>(3);
    std::cout << (a.Get<char>() == nullptr) << "\n";
    std::cout << (*a.Get<int>() == 3) << "\n";

    Any b;
    b = a;
    std::cout << (*b.Get<int>() == 3) << "\n";

    return 0;
}

Placement new

通常的new = malloc + ctor, 所以palcement new 就是在分配好的内存地址上再调用一次ctor

通常的delete = dctor + free

Vtable 的 C 实现

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
#include <stdio.h>

typedef void (*GenericFuncPtr)(void);
//use general ptr array store vf pointer

struct Cat {
    GenericFuncPtr* vtable_ptr;
};

void cat_speak(struct Cat* this) {
    printf("miao");
}

void cat_die(struct Cat* this) {
    printf("ewww");
}

GenericFuncPtr cat_vtable[] = {
    // do in the compile time
    (GenericFuncPtr)cat_speak,
    (GenericFuncPtr)cat_die,
};

void construct_cat(struct Cat* c) {
    c->vtable_ptr = cat_vtable;
}

struct Lion {
    struct Cat base;
};

void lion_speak(struct Lion* this) {
    printf("ow");
}

void lion_die(struct Lion* this) {
    printf("ahhh");
}

GenericFuncPtr lion_vtable[] = {
    (GenericFuncPtr)lion_speak,
    (GenericFuncPtr)lion_die,
};

void construct_lion(struct Lion* l) {
    construct_cat(&l->base);
    l->base.vtable_ptr = lion_vtable;
}

int main () {
    struct Lion l;
    struct Cat* c;
    construct_lion(&l);
    c = &l.base;
    // c->speak
    ((void (*)(struct Lion*))c->vtable_ptr[0])((struct Lion*)c);
    // c->die
    ((void (*)(struct Lion*))c->vtable_ptr[1])((struct Lion*)c);
    return 0;
}

Partial specialization

Partial specialization 只是针对模版参数,而且function不支持partial specialization.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename _Tp> // primary
class A {
};

template <typename _Tp>
class A<_Tp[]> {
};

template <typename _Tp>
class A<_Tp*> {
};

//template <typename _Tp> //error
//class A<_Tp> {
//};

Universal ref

1
2
3
4
5
6
7
8
9
template<typename T>
struct A {
    void Foo(T&& /*rvalue ref*/);
};
struct A {
    template<typename T>
      void Foo(T&& /*forwarding ref, or `universal ref`*/);
};
//上面的例子虽然T是模板参数,但不是等着被推出来的。

Variadic functions

用法与用处。

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
#include <iostream>
template <typename T>
class A {
public:
  A() { std::cout << "without size" << "\n"; }
  A(size_t size) { std::cout << "with size" << "\n"; }
  A(size_t size, size_t idx) { std::cout << "with size, idx" << "\n"; }
  ~A() { std::cout << "dtor" << "\n"; }
};

template <typename _Tp, typename... Args>
class B : A<_Tp> {
public:
  //B() { std::cout << "B ctor" << "\n"; } B<int>b1 wont work;
  B(Args&&... _args) : A<_Tp>(_args...) { }
private:
  //A<_Tp> _a;
};

class Tmp {
public:
  Tmp() { std::cout << "Tmp ctor" << "\n"; }
};

int main () {
    //B<int> b1;
    B<int,size_t> b2(1);
    //B<int,size_t> b(1,2); //error
    B<int,size_t,size_t> b3(1,2);

    Tmp tmp;
    Tmp tmp1(); // function !!!!!!!!!!!!
}

function specialization