学习点 C++ 11 的特性

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值