[toc]

std::reverse

  • Reverses the order of the elements in the range [first,last).

Demo

全部反转_demo++view raw
1
2
void Method2_erase() {
vector<int> data = ConstructVector();
部分反转_demo++view raw
1
// 再次打印更新后 vector 容器的大小和容量

源码

源码下载

源码下载

编译

1
2
cd 文件下载目录
g++ vector_reverse.cpp -o test --std=c++14

[toc]

clear

  • A reallocation is not guaranteed to happen, and the vector capacity is not guaranteed to change due to calling this function.

测试

clear demo++view raw
1
2
3
4
5
6
7
8
9
10
11
12
void Method1_clear() {
vector<int> data = ConstructVector();
// 打印 vector 容器的大小和容量
std::cout << "original: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;

data.clear();

// 再次打印更新后 vector 容器的大小和容量
std::cout << "new: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;
}

输出

1
2
3
Method 1
original: size = 5 ; capacity = 5
new: size = 0 ; capacity = 5

erase

  • Removes from the vector either a single element (position) or a range of elements ([first,last)).

  • An iterator pointing to the new location of the element that followed the last element erased by the function call.

测试

erase demo++view raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void Method2_erase() {
vector<int> data = ConstructVector();
// 打印 vector 容器的大小和容量
std::cout << "original: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;

for (auto iter = data.begin(); iter != data.end();) {
iter = data.erase(iter);
}

// 再次打印更新后 vector 容器的大小和容量
std::cout << "new: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;

vector<int> data1 = ConstructVector();
data1.erase(data1.begin(), data1.begin() + 2);

std::cout << "new: size = " << data1.size()
<< " ; capacity = " << data1.capacity() << std::endl;
}

输出

1
2
3
4
Method 2
original: size = 5 ; capacity = 5
new: size = 0 ; capacity = 5
new: size = 3 ; capacity = 5

swap

  • Exchanges the content of the container by the content of x, which is another vector object of the same type. Sizes may differ.

  • After the call to this member function, the elements in this container are those which were in x before the call, and the elements of x are those which were in this. All iterators, references and pointers remain valid for the swapped objects.

测试

erase demo++view raw
1
2
3
4
5
6
7
8
9
10
11
12
void Method3_swap() {
vector<int> data = ConstructVector();
// 打印 vector 容器的大小和容量
std::cout << "original: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;

vector<int>().swap(data);

// 再次打印更新后 vector 容器的大小和容量
std::cout << "new: size = " << data.size()
<< " ; capacity = " << data.capacity() << std::endl;
}

输出

1
2
3
Method 3
original: size = 5 ; capacity = 5
new: size = 0 ; capacity = 0

区别

  • vector 内存占用空间只会增长,不会减小。比如你首先分配了 10,000 个字节,然后 erase 掉后面 9,999 个,则虽然有效元素只有一个,但是内存占用仍为 10,000 个。所有空间在 vector 析构时回收。
  • 如果想清空原来数据占用的空间,我们可以通过交换技术 swap, 就是通过交换函数 swap (),使得 vector 离开其自身的作用域,从而强制释放 vector 所占的内存空间.

源码

源码下载

源码下载

编译

1
2
cd 文件下载目录
g++ vector_clear.cpp -o test --std=c++14

Reference

周五晚上从北京乘火车出发,第二天早晨到达大连火车站;在大连游玩三天,第三天晚上乘高铁返回北京,游览了大连知名的星海广场、海之韵公园,棒棰岛等景点,品尝了炒闷子等美食,还能在市区近距离喂野生鹿,非常开心的旅行。

Read more »

Package

  • You can add an optional package specifier to a .proto file to prevent name clashes between protocol message types.
  • In C++ the generated classes are wrapped inside a C++ namespace.
    • 即 package 指定的路径,会被转换为 namespace,来避免命名冲突。

Arena Allocation

  • 功能:Arena allocation is a C++-only feature that helps you optimize your memory usage and improve performance when working with protocol buffers.
  • 原因:By default, protocol buffers performs heap allocations for each message object, each of its subobjects, and several field types, such as strings. These allocations occur in bulk when parsing a message and when building new messages in memory, and associated deallocations happen when messages and their subobject trees are freed.
    • Message 的构造和释放在堆栈上进行,涉及到动态内存的生成和释放,这一步骤非常昂贵。

Python

Enum

Could not serialize object: TypeError: can't pickle google.protobuf.pyext._message.EnumDescriptor objects

我在实际 spark 上处理数据时,报错 "Could not serialize object: TypeError: can't pickle google.protobuf.pyext._message.EnumDescriptor objects", 通过报错信息,很明确这是在实际 python 代码中引用 enum 导致的问题.

enum_test.protoview raw
1
# Add code later

参考教程

在工作和生活中,我们经常需要在外部访问我们家中的主机。然而,由于主机处于内网中,外部设备 (公网) 很难直接连接到主机以获取所需的资料。

本文将介绍一种通过内网穿透软件来搭建内网服务的方法,使得外部用户能够方便地访问和使用内网中的服务和资源。在这个过程中,将会涉及到内网穿透和反向代理的核心技术。

通过调研不同的 内网穿透工具,目前主要分为两种类型:

  • 一种是通过销售硬件设备和流量的方式实现,比如快解析、花生壳、神卓互联、NAT123 等。这些工具拥有自主研发的核心技术,可以在淘宝等平台直接购买和配置。然而,这种方式的缺点是需要付费购买硬件设备,并且免费流量有限制,适合一些专业用户或氪金用户。

  • 一种是使用免费开源软件(如 frp 和 nps)来搭建内网穿透,不需要额外购买硬件设备,但需要具备公网 IP 的条件。这种方式的优点在于可以根据自己的需求进行定制化配置,后续扩展性强, 但对于新手来说入门门槛较高。

考虑到使用开源软件的优点,我的本地主机没有敏感信息,流量不设限制, 所以我选择了免费开源软件 -- frp 来搭建内网穿透服务。请注意,虽然 frp 目前使用广泛,但是本身逻辑设计有先天性缺陷,网络安全性差, 非常容易造成网络堵塞,不能长时间连接使用,技术不够成熟.

我的应用场景

  • 在办公室或外出办公时,能够通过远程 ssh 控制家中的另一台电脑;
  • 家中电脑上运行了一个 web 服务,希望能够让非局域网的用户访问到这个服务。

工具和材料

  • 一个云服务器(包含公网 IP);
  • 本地电脑需要联网;
  • 一个域名(用于多个 web 服务,如果只有 ssh 访问则不需要)。

请注意,以下的教程适合具备一定计算机基础的开发者,对于新手来说可能存在一定的配置难度。

我的网络配置示意图

我进行了如下的网络配置,以实现通过 frp 在远程访问家中的主机和使用 web 服务的目标。比如,在 ipad 上就可以通过网页连接内网服务上的 stable diffusion 生成图片。具体示意图如下:

frp 是什么?

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

内网穿透是什么?

内网穿透,即 NAT(Network Address Translator)穿透,是指计算机在内网(局域网)内使用私有 IP 地址,在连接外网(互联网)时使用全局 IP 地址的技术。简而言之,内网穿透可以将内网中的服务暴露到公网,使得这些服务可以通过公网访问。

反向代理是什么?

反向代理(reverse proxy)是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

frp 安装

你可以参考 安装教程 中的详细步骤来下载、部署和配置 frp。该教程提供了安装和开机自启动的指导,具有很好的实用性。

我的配置环境

frp 服务端:

操作系统:Ubuntu 20.04

frp 客户端设备 #1:

操作系统:Ubuntu 20.04

frp 客户端设备 #2:

操作系统:Ubuntu 22.04

如何设置 frp 支持多个本地网页终端

在我本地的开发机器 #2 ,部署了 stable diffusion 和 Jupyter Notebook 两个 web 应用,它们通过指定的本地端口提供服务,例如通过 127.0.0.1:8080 可以访问 jupyter。由于这些应用都部署在本地,无法直接从公网访问,因此 #2 主机需要配置 frpc 服务来支持公网访问。

多 web 服务主机配置

在 #2 的 frp 的配置文件(frpc.ini)添加下面的内容

[frpc.ini]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

[common]
server_addr = 1.2.3.4 # 替换成公网 IP
server_port = 1234 # 替换成开放的 Port
# 此处省去 token 等配置

[web1] # 此处配置用于远程访问内网电脑上的 A 服务
type = http
local_ip = 127.0.0.1
local_port = port1
custom_domains = a.my_domain.com

[web2] # 此处配置用于远程访问内网电脑上的 B 服务
type = http
local_ip = 127.0.0.1
local_port = port2
custom_domains = b.my_domain.com

在上述配置中,我们使用不同的 custom_domains(例如 a.my_domain.comb.my_domain.com)以及不同的 local_port(例如 88889999)来区分两个本地网页终端。在实际应用中,通过 custom_domains:vhost_http_port 就可以访问内网的 web 项目.

VPS 服务器配置

在 frp 服务器上配置相应的转发规则,将请求转发到本地网页终端。你可以在 frps.ini 配置文件中进行设置。

[frps.ini]
1
2
3
4
5
6
7
8
[common]
bind_port = 1234
token = xxxx
vhost_http_port = 8888
dashboard_port = xxxx
dashboard_user = xxxx
dashboard_pwd = xxxx

通过以上配置,你可以通过 a.my_domain.com:8888 访问第一个本地网页终端,通过 b.my_domain.com:8888 访问第二个本地网页终端。

frp 如何支持多个服务端

如果你想要支持多个服务端,需要在每个客户端安装一个 frpc 服务,并根据每个设备的差异进行配置,确保每个设备的 remote_port 不重复即可。

上文提到,本地有两台主机,如果想让两台主机都可以远程访问, 需要在每个客户端安装一个 frpc 服务.

设备 #1

[frpc.ini]
1
2
3
4
5
6
7
8
9
10
11
12

[common]
server_addr = 1.2.3.4 # 替换成公网 IP
server_port = 1234 # 替换成开放的 Port
# 此处省去 token 等配置

[ssh1] # 若有多个客户端,名称不要重复。
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 2345 # 远程连接端口不要重复

设备 #2

[frpc.ini]
1
2
3
4
5
6
7
8
9
10
11
12
13
14

[common]
server_addr = 1.2.3.4 # 替换成公网 IP
server_port = 1234 # 替换成开放的 Port
# 此处省去 token 等配置

[ssh2] # 若有多个客户端,名称不要重复。
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 3456 # 远程连接端口不要重复

# 此处省去 web 等配置

VPS 服务器配置

[frps.ini]
1
2
3
4
5
6
7
8
[common]
bind_port = 1234
token = xxxx
vhost_http_port = 8080
dashboard_port = xxxx
dashboard_user = xxxx
dashboard_pwd = xxxx

根据提供的示例,两台机器都绑定服务器的 1234 端口,但是远程连接的端口不同,第一台机器的远程连接端口为 2345,第二台机器的远程连接端口为 3456。假设 #1 用户名为 test1, #2 用户名为 test2, 那么

[#1 机器连接]
1
ssh  -oPort=2345 test1@1.2.3.4
[#2 机器连接]
1
ssh  -oPort=3456 test2@1.2.3.4

安全性

参考资料

什么是 Snap

Snap 包是 Ubuntu 16.04 LTS 发布时引入的新应用格式包。

当你在安装完 snap 后,你会发现在在根目录下会出现如 /dev/loop0、/dev/loop1 等挂载点,这些挂载点正是 snap 软件包的目录。Snap 使用了 squashFS 文件系统,一种开源的压缩,只读文件系统,基于 GPL 协议发行。一旦 snap 被安装后,其就有一个只读的文件系统和一个可写入的区域。应用自身的执行文件、库、依赖包都被放在这个只读目录,意味着该目录不能被随意篡改和写入。

较传统 Linux 的 rpm,deb 软件包,snap 引入 squashFS 文件系统,使得 snap 的安全性要优于传统的 Linux 软件包。同时,每个 snap 默认都被严格限制(confined),即限制系统权限和资源访问。但是,可通过授予权限策略来获得对系统资源的访问。

使用 snap 包的另一好处就是它类似一个容器拥有一个应用程序所有的文件和库,各个应用程序之间完全独立;解决了应用程序之间的依赖问题,使应用程序之间更容易管理,但是由此带来的问题就是它占用更多的磁盘空间。

Install Shutter Screenshot Tool

Installing Shutter on Ubuntu 20.04 & 18.04

https://itsfoss.com/install-shutter-ubuntu/ Installing Shutter on Ubuntu 20.04 & 18.04
1
2
3
4
// Shutter is not available in Ubuntu 20.04.
sudo add-apt-repository ppa:linuxuprising/shutter
sudo apt update
sudo apt install shutter

切换 Python 环境

https://www.cnblogs.com/liuzhenbo/p/13176869.html ubuntu 切换 python 版本
1
2
3
4
5
6
7
8
// 查看你系统中有哪些Python的二进制文件可供使用
ls /usr/bin/python*
// 查看python替换版本信息
update-alternatives --list python
// 使用以下命令随时在列出的python替换版本中任意切换
sudo update-alternatives --config python
// 再查一下默认Python版本
python --version

用 aptitude 代替 apt-get 处理依赖性问题

  • aptitude 与 apt-get 一样,是 Debian 及其衍生系统中功能极其强大的包管理工具。与 apt-get 不同的是,aptitude 在处理依赖问题上更佳一些。举例来说,aptitude 在删除一个包时,会同时删除本身所依赖的包。这样,系统中不会残留无用的包,整个系统更为干净。
  • 注意事项
  • 为什么可以这么做

[toc]

目前手上有一台国外 VPS,我在 19 年开始在 VPS 上部署个人网站。之前利用这个 VPS 部署本地编译好的静态网页,流程大概是

  • 本地电脑配置 hexo 环境,在本地编辑并生成静态网页;
  • 通过 git hook 等方式把本地生成的静态网页同步到远端服务器上;
  • 服务器通过 nginx 支持访问静态网页内容。

这种部署方式对多终端用户不友好,比如

  • 有时候想在手机或者其他终端上简单修改网站内容,但是配置 hexo 环境的电脑不在手边,往往需要把想更新的内容记下来,找个专门时间更新下内容,这样子容易导致自己忘记,做事情不连贯。
  • 如果有多台电脑,只能在配备有 hexo 环境的电脑上编辑;即使多台电脑配备有 hexo 内容,也容易有数据不同步的问题。

本文介绍一种方式,

  • 网站原始数据保存在 github,支持多终端访问和数据管理。
  • 远程 VPS 上部署整套 hexo 环境,支持生成静态网页结果。
  • VPS 上获取网站数据 (通常是 source 下面的数据),生成博客内容,启动 hexo 内置的 web 服务器(或使用 nginx 指向生成的 public 目录),对外提供访问。
  • 对于生成好的内容,部署到 Github (用作备份)上

这种方法可以在多终端实时更新网站内容,摆脱对单一终端的依赖,能够支持

  • VPS 上部署 hexo 环境,支持跨平台、多终端的网站内容编辑和更新。
  • 引入 git 管理网站原始数据,支持数据统一和备份。
  • 支持在 github 和 VPS 等多地同时部署个人网站,不必局限于 VPS。
Read more »

[toc]

红黑树

什么是红黑树

set/multiset 实现最大堆

在 STL 中,set 和 multiset 是基于红黑树实现的。

  • Sets are usually implemented as red-black trees.
  • Sorting is done using the key comparison function Compare. Search, removal, and insertion operations have logarithmic complexity.

Code Example

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>
#include <ostream>
#include <set>

int main() {
// Initialize a set.
// Compare parameter is default to std::less<Key>.
std::set<int> min_s;
min_s.insert(1);
min_s.insert(3);
min_s.insert(2);
min_s.insert(5);
min_s.insert(4);
min_s.insert(-1);

std::cout << "min value of set container is " << *min_s.begin() << std::endl;
std::cout << "max value of set container is " << *min_s.rbegin() << std::endl;

// Compare parameter is default to std::greater<Key>.
std::set<int, std::greater<int>> max_s;
max_s.insert(1);
max_s.insert(3);
max_s.insert(2);
max_s.insert(5);
max_s.insert(4);
max_s.insert(-1);

std::cout << "max value of set container is " << *max_s.begin() << std::endl;
std::cout << "min value of set container is " << *max_s.rbegin() << std::endl;

// Initialize a multiset.
std::multiset<int, std::greater<int>> max_ms;
max_ms.insert(1);
max_ms.insert(3);
max_ms.insert(2);
max_ms.insert(5);
max_ms.insert(4);
max_ms.insert(-1);

std::cout << "max value of multiset container is " << *max_ms.begin()
<< std::endl;
std::cout << "min value of multiset container is " << *max_ms.rbegin()
<< std::endl;

return 0;
}

输出结果如下

1
2
3
4
5
6
min value of set container is -1
max value of set container is 5
max value of set container is 5
min value of set container is -1
max value of multiset container is 5
min value of multiset container is -1

参考 <剑指 offer> 面试题 40 — 最小的 k 个数

基于 STL 的函数 push_heap、pop_heap 和 vector 实现堆

参考 <剑指 offer> 面试题 41 — 数据流中的中位数

更改记录

2023.04.02 搭建架子,写出 set 版本。

0%