初识c++

1. 2023/7/13

1.1. Contribut

  1. public/private/protected cpp
  2. friend cpp
  3. non-virtual function cpp
    1
    2
    virtual void example () {
    }const = 0;

2. 2023/7/14

2.1. cpp learning

  • stringstream
    used to split word

    using namespace std;

  • to_string(int):change a int to a string

    仅作测试样例

    1
    2
    3
    4
    int main()
    {
    printf("%-3d",a);
    }

  • 字典树 查找匹配字符,其实就是树节点存储26个字母

    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
     class Solution {
    struct Trie {
    bool isEnd;
    vector<Trie*> children;
    Trie() : isEnd(false), children(26, NULL){}
    };

    string searhPrefix(Trie* root, const string& word) {
    Trie* cur = root;
    string res;
    for (char c : word) {
    if (cur->children[c - 'a'] == NULL) {
    return "isNotMatch";
    }
    res += c;
    cur = cur->children[c - 'a'];
    if (cur->isEnd == true) return res;
    }
    return "isNotMatch";
    }
    public:
    string replaceWords(vector<string>& dictionary, string sentence) {
    // 构建前缀树Trie
    Trie* root = new Trie();
    for (string& str : dictionary) {
    Trie* cur = root;
    for (char c : str) {
    if (cur->children[c - 'a'] == NULL) {
    cur->children[c - 'a'] = new Trie();
    }
    cur = cur->children[c - 'a'];
    }
    cur->isEnd = true;
    }
    // 分割字符串
    string word, res;
    stringstream input(sentence);
    while (input >> word) {
    // 查找前缀prefix
    string prefix = searhPrefix(root, word);
    if (prefix != "isNotMatch") {
    res += prefix;
    } else {
    res += word;
    }
    res += " ";
    }
    res.pop_back();
    return res;
    }
    };

  • nullptr 纯右值(need to study)

  • 预编译->编译(目标文件obj,机器代码,可通过译码变为汇编指令)->链接

  • using Func = int (*)(int,int) 函数指针

  • using 和 typedef 的区别在于typedef只能定义类型别,,using可以定义模板别名

3. 2023/7/20

1
2
3
4
5
6
7
8
9
template <typename T, typename U>
struct ComplexType {
T value;
U otherValue;
};

// 使用 using 定义模板别名
template <typename T>
using MyAlias = ComplexType<T, std::vector<T>>;

  • using PI = pair<Treenode*,__uint128_t>;
  • push_back() vs emplace_back()

    push_back时vector会新建一个数组,将新元素&原vector中的元素深拷贝至新vector,原vector会被释放, 其中元素的析构函数也会被调用
    注意: 这里只适用于没有创建固定大小空间的vector,若使用vector.reverse(N),提前创建好元素个数,可以提高存取速度
    使用Reserve()而不是使用“vector vertices(3)”,因为下面的语法有时不起作用,因为类中没有定义默认构造函数。

    使用emplace_back而不是使用参数化构造函数创建对象并将其分配到不同的内存中,然后将其传递给复制构造函数,复制构造函数会将其插入到向量中。该函数可以直接插入对象,无需调用复制构造函数。

    如果构造函数接受多个参数,push_back 只接受该类型的一个对象obj, 而emplace_back 接受该类型的构造函数的参数。

4. 2023/7/24

  • vector empty是常数时间,empty()函数没有使用任何比较运算符,因此使用起来更方便,无论容器类型如何, empty() 函数都以恒定时间实现,而 size() 函数的某些实现需要 O(n) 时间复杂度,例如 list::size()。
  • size返回参数为size_t(unsigned int type),要小心其在vecotr.size()-1上使用时出现小于0的情况出现段错误的情况
  • Base(const Base& temp_obj) = delete;
  • 列表初始化(list initalize)
    • vector<int> vec{1}
    • vector<pair<int,int>> vec{{1,1}}
    • vector<pair<int,int>> vec{make_pair(1,1)}
      not the vec{(1,1)},it’s evaluated as 1
  • 逗号运算符,它是一种中缀运算符,用于对其左右两个表达式进行求值,并返回第二个表达式的值。
  • 使用声明将基类的成员引入到派生类定义中,例如将基类的受保护成员公开为派生类的公共成员。在这种情况下,nested-name-specifier必须命名所定义的基类。如果名称是基类的重载成员函数的名称,则引入具有该名称的所有基类成员函数。如果派生类已具有具有相同名称、参数列表和限定条件的成员,则派生类成员将隐藏或覆盖(不冲突)从基类引入的成员。
  • protected关键字说明成员在派生类中是可见的
    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
     #include <iostream>

    struct B
    {
    virtual void f(int) { std::cout << "B::f\n"; }
    void g(char) { std::cout << "B::g\n"; }
    void h(int) { std::cout << "B::h\n"; }
    protected:
    int m; // B::m is protected
    typedef int value_type;
    };

    struct D : B
    {
    using B::m; // D::m is public
    using B::value_type; // D::value_type is public

    using B::f;
    void f(int) { std::cout << "D::f\n"; } // D::f(int) overrides B::f(int)

    using B::g;
    void g(int) { std::cout << "D::g\n"; } // both g(int) and g(char) are visible

    using B::h;
    void h(int) { std::cout << "D::h\n"; } // D::h(int) hides B::h(int)
    };

    int main()
    {
    D d;
    B& b = d;

    // b.m = 2; // Error: B::m is protected
    d.m = 1; // protected B::m is accessible as public D::m

    b.f(1); // calls derived f()
    d.f(1); // calls derived f()
    std::cout << "----------\n";

    d.g(1); // calls derived g(int)
    d.g('a'); // calls base g(char), exposed via using B::g;
    std::cout << "----------\n";

    b.h(1); // calls base h()
    d.h(1); // calls derived h()
    }
  • 聚合初始化(aggregate initialization)
    • 指定初始化器(designated initializers)
    • four types of initializers:
      • T object{d,s,i} brace elision is prohibited 直接列表初始化
      • T object={d,s,i} 复制初始化
  • 头文件规定了uint32_t & so on

5. 2023/7/25

1
2
3
4
5
ios::sync_with_stdio(false);//c++将printf和cout绑定到同一个输出流上,为了在输出时发生混乱,默认将cout的输出先放置在缓冲区,该语句可以打消输入输出的缓存,加快输入输出效率  
ios::tie();//This unties cin from cout. Tied streams ensure that one stream is flushed automatically before each I/O operation on the other stream.
//解耦输入输出流导致当程序等待用户输入时,输出信息并没有显示在屏幕,此时可以使用 std::flush或者std::endl来刷新缓冲区
cin.tie(nullptr);
//返回值为指向在调用之前绑定的流对象的指针,或者在流未绑定的情况下为空指针。
  • c++文件与流
  • cin 与 cin.get()都会将分隔符留在输入缓冲区中
  • c++ getline
    • getline分为两类:
      std:getline string流里的 std:basic_istream isstream流里的,主要用来提取C string
      getline(cin,str,delim) cin.getline(streamsize,delim)
      存储的字符大于str.max_size()或者碰到分隔符会结束提取字符 存储的字符等于streamsize-1或者碰到分隔符会结束提取字符
      分割符会被提取但不会被存储 分隔符会被提取同时被计数
  • memcpy & memmove
    1
    2
    memcpy(array.data(),str,bytessize) //拷贝指定字节数至des
    memmove(array.data()/des,str/src,bytessize) //当src+bytessize和des有重叠字节时用memmove

6. 2023/7/26

  • queue,stack等adapter列表初始化时不能直接使用brace,要先使用brace将其转化为底层容器,再用小括号将其转化为adapter
    queue myqueue({1,2,3})

  • 同一行不能用逗号隔开两个不同类型变量的定义或声明

  • c++中类static member有关问题

  • 并查集的标准写法

    • 私有成员成员vector也可以通过列表成员初始化进行初始化
    • iota:对序列中的元素进行值递增操作
      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
      class UF {
      public:
      vector<int> fa;
      vector<int> sz;
      int n;
      int comp_cnt;

      public:
      UF(int _n): n(_n), comp_cnt(_n), fa(_n), sz(_n, 1) {
      iota(fa.begin(), fa.end(), 0);
      }

      int findset(int x) {
      return fa[x] == x ? x : fa[x] = findset(fa[x]);
      }

      void unite(int x, int y) {
      x = findset(x);
      y = findset(y);
      if (x == y) {
      return;
      }
      if (sz[x] < sz[y]) {
      swap(x, y);
      }
      fa[y] = x;
      sz[x] += sz[y];
      --comp_cnt;
      }

      bool connected(int x, int y) {
      x = findset(x);
      y = findset(y);
      return x == y;
      }
      };
  • 结构化绑定

    • auto [x, y] = q.front();//无需使用q.front().first
  • vector.erase(std::unique(vector.begin(), vector.end()),vector.end());


初识c++
http://example.com/2023/07/24/introduction/
作者
李凯华
发布于
2023年7月24日
许可协议