0%

C++杂记

C++功能强大、特性丰富,但总有一些语法、函数在偶尔用到的时候记不住需要现查,频繁打断工作流颇为恼人,在这里做一些记录,希望能加强记忆、提高效率。

ltrim与rtrim

C++没有提供原生的字符串trim方法,但是可以用stl库里的方法快速实现ltrimrtrim

1
2
3
4
5
6
7
8
9
10
11
12
13
inline void ltrim(std::string &s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch){
return !std::isspace(ch);
}));
}

inline void rtrim(std::string &s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch){
return !std::isspace(ch);
}).base(), s.rend());
}

std::vector的构造函数

构造有n个值为val的元素的vector的构造函数为:

1
vector(size_t count, const T& value);

数量在前,值在后。可以可以记忆中文语法里惯用的“多少个什么”(“三个苹果”)来记住参数的顺序。

如果想构造一个只有一个元素的vector,就不要用上面那个构造函数了,vector也是可以用初始化列表的!

1
vector<string> strs{string("yayaya")};

有用的<cctype>

cctype头文件中提供了大量有关字符的工具函数:isspace, isalpha, isdigit, isalnum, tolower, isuppe,要用这些函数时无需自己编写。

std::map的增强型for循环

std::map的基本单元为std::pair,其增强型for循环应这样写:

1
2
3
4
5
6
7
map<int, char> int2str = {
{1, "one"},
{2, "two"},
{3, "three"}
};
for(auto &pair: int2str)
printf("key: %d, val: %s\n", pair.first, pair.second.c_str());

基于迭代器的普通for循环亦参照此。

stringstream

使用std::stringstream需要包含头文件<sstream>

1
#include <sstream>

可以使用默认构造或者字符串构造。

1
2
std::stringstream ss; 
std::stringstream ss("Hello, world!");

使用str()方法获取流中的字符串内容。
使用clear()方法清空流。
可以对std::string进行流插入。

格式化字符串

C++20中,std库终于提供了生成格式化std::string对象的方法std::format

1
2
3
std::string formatString(int number, const std::string& text) {
return std::format("Number: {}, Text: {}", number, text);
}

std::format中不能使用%d %c这样的格式控制符,因此另附std::format的格式控制符表:

{}: 默认格式化(适用于大多数类型)
{0}: 按照索引格式化(支持多参数时指定)
{:d}: 格式化为整数
{:f}: 格式化为浮点数
{:s}: 格式化为字符串
{:x}: 格式化为十六进制整数
{:X}: 格式化为十六进制整数(大写)
{:e}: 格式化为科学记数法
{:c}: 格式化为字符
{:>width}: 右对齐,宽度为 width
{:<width}: 左对齐,宽度为 width
{:^width}: 居中对齐,宽度为 width
{:0width}: 用零填充空白部分,宽度为 width

类模板的实现不与声明分离

在以往的C++实践中,写类时已经习惯了.h里成员函数的声明,.cpp里写成员函数的实现,但是这对类模板并不适用,类模板成员函数的实现也内联在.h中,否则需要在.cpp文件的末尾显式地实例化要用的模板,否则报undefined reference

向std::vector中填充元素

在向各种STL容器中填充元素时可以使用std:fill方法,其原型为:

1
void std::fill(iterator __first, iterator __last, ... &__value);

std::vector独有assign()方法:

1
void std::vector::assign(size_t count, const T& value);

另甚至有生成器方法:

1
2
std::generate(RandomAccessIterator first, RandomAccessIterator last, Generator&& gen);
std::generate(vec.begin(), vec.end(), [&counter]() { return counter++; });

顺带一提,什么最大值最小值的方法也是有的,当然也能自己附加比较器。

1
2
template<class ForwardIterator>
ForwardIterator max_element( ForwardIterator first, ForwardIterator last );

在以往的C++实践中,写类时已经习惯了.h里成员函数的声明,.cpp里写成员函数的实现,但是这对类模板并不适用,类模板成员函数的实现也内联在.h中,否则需要在.cpp文件的末尾显式地实例化要用的模板,否则编译报undefined reference

平台无关的固定位数整数

要定义平台无关的固定位数整数,通常使用uint64_t int32_t等,这些类型定义在头文件<cstdint>中。