std::vector<T,Allocator>::::emplace_back
干的活和 std::vector<T,Allocator>::push_back
一样,都是在容器里增加一个元素。不同之处在于,emplace_back
的参数是对象的构造函数参数,这样就避免了在堆栈上构造一个临时对象,然后拷贝到容器中的开销。
小知识:为什么早期 C++ 不支持这个?
因为 C++11 后才支持变长参数模板。
本函数需要这个特效的支持:emplace_back(Args&&… args);
本函数常见于各种较新的数据库内核中,如 ClickHouse。
关于 emplace_back 更深刻一点的解析见 https://scenery.pcwanli.com/front/article/9446.html
std::move
左值引用的声明符号为 & ,右值引用的声明符号为 && 。
这个东西没有什么神奇的,std::move 是一个编译期类型 cast 封装,它指示调用右值接口。
STL 的容器、对象(string等)都全面支持了右值接口,使得 move 语义的支持可以在 STL 中形成一个体系:拷贝栈数据,不拷贝堆数据,转移堆数据的所有权。
关于 move,这篇文章写得最好:https://juejin.cn/post/7192171206030819385
看个例子:
[xiaochu.yh ~/tools/cpp] $g++ move.cpp -std=c++11
[xiaochu.yh ~/tools/cpp] $./a.out
ptr:0xfc9028 value:wearmheart
ptr:0xfc9028 value:wearmheart
ptr:0x7f09a16333f8 value:
ptr:0xfc90c8 value:wearmheart2
[xiaochu.yh ~/tools/cpp] $cat move.cpp
#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include <string>
#include <memory>
#include <vector>
#include <iostream>
int main()
{
std::string str1 = "wearmheart";
std::vector<std::string> vec;
vec.push_back(str1); // 传统方法,copy
vec.push_back(std::move(str1)); // 调用移动语义的push_back方法,避免拷贝,str1会失去原有值,变成空字符串
vec.push_back(std::move(str1)); // 此时 str1 已经失去了原有值,指针已经非法
vec.emplace_back("wearmheart2"); // 当然可以直接接右值
for (auto v = vec.begin(); v != vec.end(); v++) {
std::cout << "ptr:" << (void *)(*v).c_str() << " value:" << *v << std::endl;
}
return 0;
}
vec 中的第一个元素、第二个元素都指向相同的字符串地址,这就是 std::move 的作用。
std::move 没有什么神奇的地方,它需要各个对象支持对应的右值接口才能正常工作。
对于 OceanBase 来说,倒是没有特别困扰,绝大多数时候,OceanBase 的容器实现本身并不关心如何拷贝 item 对象,具体行为,是由 item 对象本身的 assign 方法决定,而不是容器决定。
std::bind
这个是一个适配器,它可以代理 callable 接口:
void to_string(int n, char *promot)
{
return format("%s %n", promot, n);
};
auto b = std::bind(to_string, std::placeholder::_1, "family member count is ");
b(5);
to_string 必须接收两个参数,在某个场景里要将 to_string 传给一个对象,让对象回调 to_string。但是该对象只会使用一个参数来回调 to_string。此时可以使用 std::bind 来做适配。
initializer_list
形式上 initializer_list 和 std::vector 很像,用于记录一组值。但是它可以写成常量列表的形式:
std::initializer_list<int> params = {0,3,223,1};
template <typename T>
void f(std::initializer<T> &v)
{
for (auto i : v) { std::cout << i << endl; }
}
f(params);
总体上来说,它提供了一种比较方便的方式表达常量数组,可用于传参、初始化数组、初始化 vector 等。
简易参考:https://juejin.cn/post/7003571511025991717