本文记录C++相关的内容。
主要来源各种CPP专栏,公众号等
POD类型
包括标量类型和POD类类型
标量类型
- 算数类型
- 整数类型
- 有符号整数类型(signed char, short, int, long)
- 无符号整数类型(unsigned char, unsigned short, unsigned int, unsigned long)
- 字符类型char(char默认既不是有符号 也不是无符号)和宽字符类型wchar_t
- 布尔类型
- 浮点类型
- float double long double
- 整数类型
- 枚举类型
- 指针类型
- void*
- T*
- T(*)(….) T为返回类型
- 指针到成员类型
- 指针到非静态成员变量
- 指针到非静态成员函数
POD类类型
无用户定义的构造 析构 拷贝 赋值运算符。
无继承关系(无基类)
无虚函数(没有虚表)
左值 右值
C++中值的类别(value category)如上所示。(值类型 value type 是 int这种)
glvalue(generalized lvalue) 广义左值
lvalue 左值
函数调用时,左值可以绑定到左值引用的参数
T&
。常量只能绑定到常左值引用
const T&
- 变量,函数或者数据成员的名字
- 返回左值引用的表达式。
++x
,cout << ' '
- 字符串字面量
"hello world"
rvalue 右值
prvalue (pure rvalue)纯右值
没有标识符,不可以取地址的表达式,一般称为临时对象
纯右值可以绑定到常左值引用
const T&
将一个纯右值绑定到一个引用上,其生命周期会延长到和这个引用变量一样长。但是对于xvalue无效(
result&& r = std::move
),这样会出现BUG- 返回非引用类型的表达式
x++
,make_shared<int>(42)
- 字符串字面值以外的字面量
42
true
- 返回非引用类型的表达式
xvalue (expiring lvalue)将亡值
代表其资源能够被重新使用的范左值
- 返回类型为对象的右值引用的函数调用或重载运算符表达式 std::move(ptr1) 右值引用有标识符 虽然有标识符但仍然不能取地址
应该将一个移动构造函数实现为noexcept
不然抛出异常后,正在构造的新对象和交出资源的旧对象都可能出现了问题。导致非异常安全
临时对象会在包含其的表达式求职完成后按照生成顺序的逆序销毁(不包括生命周期延长的情况)
容器
string类一般不被认为是容易的原因:容器类可以存储任意类型的对象。
当移动构造函数被标记为noexcept的时候,vector扩容的时候会使用移动。而如果没有标记为noexcept的时候则会使用拷贝构造
void _Umove_if_noexcept(pointer _First, pointer _Last, pointer _Dest) {
// move_if_noexcept [_First, _Last) to raw _Dest, using allocator
_Umove_if_noexcept1(_First, _Last, _Dest,
bool_constant<disjunction_v<is_nothrow_move_constructible<_Ty>, negation<is_copy_constructible<_Ty>>>>{});
}
// _Umove_if_noexcept1存在两个版本
void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, false_type);
_Uninitialized_copy();
void _Umove_if_noexcept1(pointer _First, pointer _Last, pointer _Dest, true_type);
_Uninitialized_move();
关联容器中的键需要满足严格的弱序关系
- 如果a<=b 也可以得到 b<=a 两个比较值不能够同时严格弱序于对方
- 但是如果 a<b 则没有上面的问题
相对于传统数组,array在传递参数的时候不会发生退化现象。
相对于vector,array是在栈上分配空间
定制map和set
set和map需要特化hash模板 以及 实现 equal判断
unordered_set和unordered_map 需要严格弱序的 less
class Foo
{
public:
Foo(int val):
val_(val)
{
}
bool operator<(const Foo& other) const // 有序的容器都是用严格的弱序关系
{
return val_ < other.val_;
}
bool operator==(const Foo& other) const // 使用哈希表的还需要一个额外的equal
{
return val_ == other.val_;
}
int GetVal() const
{
return val_;
}
private:
int val_;
};
template<>
struct std::hash<Foo> // 模板特化
{
public:
size_t operator()(const Foo& foo) const noexcept
{
std::hash<int> hash_f;
return hash_f(foo.GetVal());
}
};
int main()
{
std::set<Foo, std::less<Foo>> foo_set;
std::unordered_set<Foo, std::hash<Foo>, std::equal_to<Foo>> foo_unoreder_set;
foo_set.insert(Foo{1});
std::find(foo_set.begin(), foo_set.end(), Foo{1});
foo_unoreder_set.insert(Foo{1});
std::find(foo_unoreder_set.begin(), foo_unoreder_set.end(), Foo{ 1 });
}