VSCode 容器中开发相关配置

本文主要讲解在容器中利用 VSCode 进行开发的一些配置, 容器的优势这里不再赘述,假设你已具备了镜像构建以及其基本操作

容器环境准备

预设以下条件

  • 代码工程目录放置在 /workspace/my_project
  • 开发环境镜像在 my_image (这里假设是一个ubuntu镜像)
1
2
3
4
5
6
7
8
9
10
cd /workspace/my_project

docker run -ti --entrypoint=/bin/bash \
--net=host \
--ipc=host \
-v $(pwd):/$(basename $(pwd)) \
-v $(pwd)/.vscode-server:/root/.vscode-server \
--privileged \
--name $(basename $(pwd))_dev \
my_image

以上会启动一个 my_project_dev 容器,并将代码挂载到了容器内的 /my_project

  • -v $(pwd)/.vscode-server:/root/.vscode-server vscode 容器开发会在容器内的 $HOME/.vscode-server 里安装一些资源或者文件,包括容器内的插件也在这里,提前挂载进去是将这部分持久化,避免重新安装

Remote-SSH 配置

另一种方法,是在容器里启一个ssh服务,然后用ssh远程连接,和连接远程服务器一样,下面是 容器内远程连接的一些说明以及配置

  1. 容器要 –net=host 启动,且要将代码挂载进容器内
  2. 要选择一个容器 ssh 端口,比如 2222,连接容器内的时候要指定端口。(22通常是宿主机的 ssh 端口)

在容器安装ssh服务并开启,下面是 ssh-rsa xxxxxxxxxxxxxxxxxxxxx 是物理机的公钥, 用于免密登录,需要替换成自己的值。

公钥通常在 $HOME/.ssh/id_rsa.pub 下,可通过 ssh-keygen 生成。

1
2
3
4
5
apt install openssh-server -y
mkdir /var/run/sshd
echo "ssh-rsa xxxxxxxxxxxxxxxxxxxxx" > /root/.ssh/authorized_keys

/usr/sbin/sshd -p 2222

物理机验证

1
ssh -p 2222 root@my_ip

验证成功后就可以使用vscode远程连接了。

C++对象模型(5): 关于数据

  • 空类也有一字节的大小,因为这才能对对象取地址
  • 一个对象的内存布局通常由三部分组成
    1. 非静态成员变量
    2. 内存对齐所填补的空间
    3. 为了支持 virtual 机制而引起的额外负担,比如 vptr
  • 传统上,vptr 被安置到所有明确声明的 member 后面,但要看具体编译器实现
  • 直观上,通过对象取值 object.xxx 比指针取值 object_point->xxx 更方便,但实际上是完全一样的,都会被编译器扩展
  • 编译器编译的时候会区分
    • 执行data member的指针,指向第一个member (object::member - 1)
    • 指向data member的指针,但是没有指向任何 member
  • 下面两种方式,有什么区别
    1
    2
    3
    4
    5
    X x; 
    x.x == 0.0;

    X *px;
    px->x = 0.0;
    当 X 中含有一个虚基类, 而且 x 正好是虚基类中的成员时,有重大区别。前者可以编译期确定 x 的 offset,但是 px 只能再运行期确定
  • 支持多态带来的负担
    1. 导入virtual table 用来存放 virtual function 地址, 这个table的元素数量一般是virtual function的数目再加上一个或两个slots(用于支持RTTI)
    2. 在每一个object中安插一个 vptr 指向 virtual table
    3. 在 constructor 中安插代码用于设置 vptr
    4. 在 deconstructor 中安插代码用于抹除 vptr

C++对象模型(3): 关于数据

  • 空类也有一字节的大小,因为这才能对对象取地址
  • 一个对象的内存布局通常由三部分组成
    1. 非静态成员变量
    2. 内存对齐所填补的空间
    3. 为了支持 virtual 机制而引起的额外负担,比如 vptr
  • 传统上,vptr 被安置到所有明确声明的 member 后面,但要看具体编译器实现
  • 直观上,通过对象取值 object.xxx 比指针取值 object_point->xxx 更方便,但实际上是完全一样的,都会被编译器扩展
  • 编译器编译的时候会区分
    • 执行data member的指针,指向第一个member (object::member - 1)
    • 指向data member的指针,但是没有指向任何 member
  • 下面两种方式,有什么区别
    1
    2
    3
    4
    5
    X x; 
    x.x == 0.0;

    X *px;
    px->x = 0.0;
    当 X 中含有一个虚基类, 而且 x 正好是虚基类中的成员时,有重大区别。前者可以编译期确定 x 的 offset,但是 px 只能再运行期确定
  • 支持多态带来的负担
    1. 导入virtual table 用来存放 virtual function 地址, 这个table的元素数量一般是virtual function的数目再加上一个或两个slots(用于支持RTTI)
    2. 在每一个object中安插一个 vptr 指向 virtual table
    3. 在 constructor 中安插代码用于设置 vptr
    4. 在 deconstructor 中安插代码用于抹除 vptr

SFINAE应用场景: 检测成员

在C++编程中,Substitution Failure Is Not An Error(SFINAE)是一种强大的技术,允许我们在编译时根据类型特征选择不同的实现。这个特性在许多现代C++库和框架中被广泛使用,其中之一是在处理不同结构的通用接口时。

让我们看一个简单而实用的例子,通过检查类型是否具有特定成员来优雅地处理不同结构的通用接口。在这个例子中,我们将使用SFINAE来检查类型是否包含名为 ‘header’ 的成员,并相应地执行不同的处理。