Post

Modern-CPP - Chapter02 - Basics

Modern-CPP - Chapter02 - Basics

课程来源:b站我是龙套小果丁

前半部分

  1. 加上-ftrapv后,溢出会被捕获,程序会abort

  2. 1
    2
    3
    4
    5
    6
    7
    
    #include <cstdint>
    #include <print>
       
    int main() {
      std::uint8_t a = 123;
      std::println("0x{:x}", reinterpret_cast<std::uintptr_t>(&a));
    }
    
  3. 1
    2
    3
    4
    5
    6
    7
    8
    
    #include <cstdint>
       
    float GetInvSqrt(float num) {
      int32_t i = *reinterpret_cast<int32_t *>(&num);
      i = 0x5f3759df - (i >> 1);
      float y = *reinterpret_cast<float *>(&i);
      return y * (1.5f - (num * 0.5f * y * y));
    }
    
  4. 1
    2
    3
    4
    5
    6
    
    template <typename T> T ToNetworkByteOrder(T value) {
      if constexpr (std::endian::native == std::endian::little) {
        return std::byteswap(value);
      }
      return value;
    }
    
  5. 自行写代码看有无报错即可

  6. 函数声明:

    1
    
    void func(int (*)(float, double));
    
  7. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    #include <utility>
       
    enum class Permission : unsigned int {
      read  = 1 << 0,  // 1
      write = 1 << 1, // 2
      exec  = 1 << 2   // 4
    };
       
    constexpr Permission operator|(Permission a, Permission b) {
      return static_cast<Permission>(std::to_underlying(a) | std::to_underlying(b));
    }
       
    constexpr Permission operator&(Permission a, Permission b) {
      return static_cast<Permission>(std::to_underlying(a) & std::to_underlying(b));
    }
    
  8. 值为0,因为等号右边的表达式会先被evaluate

后半部分

  1. 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 <compare>
    #include <print>
       
    class Vector3 {
    public:
      explicit Vector3(float x = 0.0f, float y = 0.0f, float z = 0.0f)
          : x_{x}, y_{y}, z_{z} {}
       
      Vector3 &operator+=(const Vector3 &rhs) noexcept {
        x_ += rhs.x_;
        y_ += rhs.y_;
        z_ += rhs.z_;
        return *this;
      }
       
      friend Vector3 operator+(const Vector3 &lhs, const Vector3 &rhs) noexcept {
        return Vector3{lhs.x_ + rhs.x_, lhs.y_ + rhs.y_, lhs.z_ + rhs.z_};
      }
       
      friend bool operator==(const Vector3 &lhs, const Vector3 &rhs) noexcept {
        return lhs.lengthSquared() == rhs.lengthSquared();
      }
       
      friend auto operator<=>(const Vector3 &lhs, const Vector3 &rhs) noexcept {
        return lhs.lengthSquared() <=> rhs.lengthSquared();
      }
       
      float lengthSquared() const noexcept { return x_ * x_ + y_ * y_ + z_ * z_; }
       
    private:
      float x_, y_, z_;
    };
    
  2. 可以,特别地:

    1
    2
    3
    4
    5
    6
    7
    8
    
    #include <map>
    #include <string>
    #include <unordered_map>
       
    int main() {
      std::map<std::string, int> scores{{"Alice", 95}, {"Bob", 89}, {"Carol", 92}};
      std::unordered_map<std::string, int> heights{{"Tom", 175}, {"Jerry", 165}};
    }
    
  3. 有,因为有虚指针的存在,证明:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    #include <print>
       
    class A {
      int x;
    };
       
    class B {
      int x;
      virtual void foo() {}
    };
       
    int main() {
      std::println("sizeof(A): {}", sizeof(A));
      std::println("sizeof(B): {}", sizeof(B));
    }
    

    输出:

    1
    2
    
    sizeof(A): 4
    sizeof(B): 16
    

    这里B的大小为16bytes的原因是内存对齐

  4. 不构成,只有返回值类型不同不构成重载;不会有干扰,因为有name mangling的存在,两个函数的identifier并不一样:

    1
    2
    3
    4
    5
    6
    7
    8
    
    void Test(int);
    template <typename T> T Test(int);
       
    int main() {
      Test(0);
      Test<void>(0);
      return 0;
    }
    

    编译后:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    main:
            pushq   %rbp
            movq    %rsp, %rbp
            movl    $0, %edi
            call    _Z4Testi
            movl    $0, %edi
            call    _Z4TestIvET_i
            movl    $0, %eax
            popq    %rbp
            ret
    

    可以看到两个函数的identifier并不相同

  5. 不开-O2优化:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    Foo::foo():
            pushq   %rbp
            movq    %rsp, %rbp
            movq    %rdi, -8(%rbp)
            cmpq    $0, -8(%rbp)
            je      .L2
            movl    $42, %eax
            jmp     .L4
    .L2:
            movl    $0, %eax
    .L4:
            popq    %rbp
            ret
    bar():
            pushq   %rbp
            movq    %rsp, %rbp
            subq    $16, %rsp
            movq    $0, -8(%rbp)
            movq    -8(%rbp), %rax
            movq    %rax, %rdi
            call    Foo::foo()
            leave
            ret
    

    -O2优化:

    1
    2
    3
    
    bar():
            movl    $42, %eax
            ret
    

    开启-O2优化后,编译器将this指针默认evaluate为true

    这在clang的linter里也可以发现:

    1
    
    'this' pointer cannot be null in well-defined C++ code; pointer may be assumed to always convert to true clang(-Wundefined-bool-conversion)
    
  6. 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
    
    #include <algorithm>
    #include <cstddef>
       
    template <typename T> class Array3D {
    private:
      T *data;
      size_t x_size, y_size, z_size;
       
      size_t index(size_t x, size_t y, size_t z) const {
        return x * (y_size * z_size) + y * z_size + z;
      }
       
    public:
      Array3D(size_t x, size_t y, size_t z) : x_size{x}, y_size{y}, z_size{z} {
        data = new T[x * y * z]();
      }
       
      ~Array3D() { delete[] data; }
       
      Array3D(const Array3D &other)
          : x_size{other.x_size}, y_size{other.y_size}, z_size{other.z_size} {
        size_t total_size = x_size * y_size * z_size;
        data = new T[total_size];
        std::copy(other.data, other.data + total_size, data);
      }
       
      Array3D &operator=(const Array3D &other) {
        if (this != &other) {
          T *new_data = new T[other.x_size * other.y_size * other.z_size];
       
          std::copy(other.data,
                    other.data + (other.x_size * other.y_size * other.z_size),
                    new_data);
       
          delete[] data;
       
          data = new_data;
          x_size = other.x_size;
          y_size = other.y_size;
          z_size = other.z_size;
        }
        return *this;
      }
       
      T &operator()(size_t x, size_t y, size_t z) { return data[index(x, y, z)]; }
       
      const T &operator()(size_t x, size_t y, size_t z) const {
        return data[index(x, y, z)];
      }
    };
    
  7. 1
    2
    3
    4
    5
    6
    7
    8
    
    void FillFibonacci(std::vector<int> &v) {
      std::ranges::generate(v.begin(), v.end(), [x = 0, y = 1]() mutable {
        int next = x + y;
        x = y;
        y = next;
        return x;
      });
    }
    
  8. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    enum class Color { red, blue, green };
       
    void PrintColor(Color c) {
      switch (c) {
        using enum Color;
      case red:
        [[fallthrough]];
      case green:
        std::println("Hello");
        break;
      case blue:
        std::println("World");
        break;
      }
    }
    
  9. 1
    2
    3
    4
    5
    
    void sort_vec(std::vector<DijkstraInfo> &vec) {
      std::ranges::sort(vec, [](const DijkstraInfo &a, const DijkstraInfo &b) {
        return a.distance < b.distance;
      });
    }
    

    可以等价为:

    1
    2
    3
    4
    5
    
    void sort_vec(std::vector<DijkstraInfo> &vec) {
      std::ranges::sort(vec, [](const auto &a, const auto &b) {
        return a.distance < b.distance;
      });
    }
    

    因为vec的类型为std::vector<DijkstraInfo>,编译器能推导出auto的实际类型

    若有如下函数:

    1
    2
    3
    
    bool Func(const auto &a, const auto &b) {
      return a.distance < b.distance;
    }
    

    他不能传入sort,因为这是个模版函数,编译器不知道用什么实例函数

    对于该模版:

    1
    2
    3
    4
    5
    
    template <typename T> struct Functor {
      static bool operator()(const T &a, const T &b) {
        return a.distance < b.distance;
      }
    };
    

    必须要进行实例化:

    1
    2
    3
    
    void sort_vec(std::vector<DijkstraInfo> &vec) {
      std::sort(vec.begin(), vec.end(), Functor<DijkstraInfo>());
    }
    

    因为Functor是一个类模版,编译器无法推导出具体类型

  10. 因为传递的是引用,改为值传递即可:

    1
    2
    3
    4
    5
    6
    
    CudaMalloc(&_raw_ptr, _buffer_size);
    _storage = std::make_shared<NDArrayStorage>(BorrowToMemoryPool(
        local_device, _raw_ptr, _buffer_size, [raw_ptr = _raw_ptr](DataPtr data_ptr) {
            hetu::cuda::CUDADeviceGuard guard(local_device.index());
            CudaFree(raw_ptr);
        }));
    
This post is licensed under CC BY 4.0 by the author.