language/implicit_conversion 限定性类型转换
写在前面
内容见 implicit conversion。
限定性转换指的是和 cv 属性有关的类型转换,它的发生必须满足一定的条件。
相似类型
忽略掉各层的 cv 属性,如果两个类型形式相同,就是相似类型。比如 const int* volatile *
和 int** const
。
Important
函数指针对应函数的参数和返回值类型的 cv 属性不可以忽略。可见原页面的例子,这里略去。
内容见 implicit conversion。
限定性转换指的是和 cv 属性有关的类型转换,它的发生必须满足一定的条件。
忽略掉各层的 cv 属性,如果两个类型形式相同,就是相似类型。比如 const int* volatile *
和 int** const
。
Important
函数指针对应函数的参数和返回值类型的 cv 属性不可以忽略。可见原页面的例子,这里略去。
-Wnrvo
编译参数。返回值(或函数参数)的位置,如果表达式是纯右值,且返回值(或函数参数)需要的也是同一类型的纯右值,那么标准就要求省略复制和移动。不过,为了让语义检查通过,要构造对象的析构函数必须在此处可以访问,尽管在完成优化之后并不会用到析构函数。
T f()
{
return U(); // constructs a temporary of type U,
// then initializes the returned T from the temporary
}
T g()
{
return T(); // constructs the returned T directly; no move
}
T x = T(T(f())); // x is initialized by the result of f() directly; no move
The C++17 core language specification of prvalues and temporaries is fundamentally different from that of earlier C++ revisions: there is no longer a temporary to copy/move from. Another way to describe C++17 mechanics is “unmaterialized value passing” or “deferred temporary materialization”: prvalues are returned and used without ever materializing a temporary.
编译器一些场景可以对 copy/move 进行省略,但不是强制的(实测 gcc 和 clang 在默认优化等级下就会使用这项优化,而 MSVC 则是在 /O2
才会启用这项优化)。当这项优化发生时,复制 / 移动构造函数必须是可用的,尽管不会被实际执行。
这个问题在 Windows MSYS2 中没有出现,但是在 WSL 上出现了。在调试时对 std::vector
的显示如下:
本来我是用的 CMake 上的调试启动功能的,StackOverflow 上面让用 .vscode/launch.json,我也试了,但是同样不行。这是我写的启动文件内容,主要是在 setupCommands
中打开了 pretty-printing 功能:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
"version": "0.2.0",
"configurations": [
{
"name": "gdb - debug active file",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/main",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"setupCommands": [
{ // Display content in STL containers pretty
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
// "preLaunchTask": "C/C++: g++ build active file"
}
]
}
按照 StackOverflow 的 回答 1,我在 gdb 中用 info pretty-printer
看当前支持的 pretty-printer。结果:
假设是 3 号卡,用 sudo lsof /dev/nvidia3
看看有哪些进程正在使用这个设备。然后用各种手段查看各个可疑进程的信息(假设进程号是 66666):
ps ww 66666
(BSD 风格的 ps
,而不是 System V)。cat /proc/66666/status
查看进程状态。除了 status 之外,还有其他信息可以在 /proc 下查看。htop -p 66666
或者 top -p 66666
。确定进程没用之后,就可以根据 PID 杀掉进程了。
Tip
除了 lsof
之外,还可以用 fuser
查找正打开文件或者 socket 的进程。根据 https://unix.stackexchange.com/a/60497/ ,lsof
更适合找一个进程打开的所有的文件,而 fuser
更适合找特定文件被什么进程打开了,比如 fuser -uv
,详见刚刚的链接。
在 Debian 下使用 fuser
需要安装 psmisc(pstree
也是这个包)。
如果不给管理员权限,lsof
可能会输出错误信息并遗漏内容,fuser
则可能会静默失败。
现象:在 nvidia-smi
上查不到,在 nvitop
上能查到但显示“No Such Process”。
https://en.cppreference.com/w/cpp/language/rule_of_three
析构函数、拷贝构造、拷贝赋值三者要是定义了其一,最好把其他两个都补上,因为编译生成的很可能不是我们想要的。此外,定义三者之一会导致移动构造、移动赋值被删除。
Note
显式删除拷贝构造函数(MyClass(const MyClass&) = delete;
)也是一种声明,这样会导致移动构造函数被删除,如果有移动尝试则会匹配上(被删除的)拷贝构造函数,从而编译失败。
Tip
复制 / 移动赋值操作符可以用复制 / 移动构造函数 + std::swap
实现。
Docker 不能用 CTRL + p,CTRL + q 退出的解决方案:登录后先用 tty
看自己的终端。然后用另外一个连接 ps -af
看想要终止的 docker
命令的 pid 是多少,然后用 kill -9
强杀。因为杀的是客户端而不是守护进程,所以不需要担心其他正在运行的容器受到影响。
Warning
不能用 kill
(不带参数),因为 kill
会让 docker 连接优雅退出,所以容器也会被关闭!
这样能更快找到 docker 命令:
ps -af|grep -iE '(pid|docker)' --color=always|grep -v "grep --color="
docker stats
可以实时刷新所有容器的占用情况。用 docker stats --no-stream
只看最近一次,而不像 top
一样刷新。不知道哪个容器占用多的时候可以使用这个命令。
我们实验室的不同学生使用不同的容器作为开发环境。现在的问题是,当我们从 htop
或者 top
中发现某个进程消耗了大量资源时,我们需要确定这个进程是由哪个容器启动的,怎么做呢?
用 pstree -sg
找到进程的父进程,然后在运行的容器中找有没有谁的进程号是能对应的上的。
经过学长提醒,我认识到还可以用 cat /proc/<pid>/cgroup
来查看进程关联信息的方法。如果进程是在容器内运行,输出路径中会包含容器的 id。
https://godbolt.org/z/YrzsWbMh8
在以下几种编译器上都尝试了:
发现只有 x86 msvc v19.38 给函数名前面加了下划线,其他几种编译器都是尊重函数定义的名字。以前做川合秀实的 30 天自制操作系统时,还以为所有编译器都会固定地给 C 语言函数名前面加上下划线,所以汇编中引用时有一些区别。现在看来只是因为平台不同,所以编译器处理方式也不同。
有两种方案,推荐第 2 种。
截至 2024 年 3 月 14 日 最新的 docker-compose 文件是 https://raw.githubusercontent.com/overleaf/overleaf/408e1dccd7c0cb58fe02c5eb9ef983312ad9b244/docker-compose.yml
首先把 docker-compose 配置文件下载下来修改好 sharelatex 的端口、sharelatex/redis/mongo 的映射路径。
❗ 问题:连接不上 redis。这是因为 sharelatex 仍在使用 SHARELATEX
开头的环境变量,所以要把 OVERLEAF
开头的环境变量复制一份改个前缀。改好之后又提示 mongo 连接不上,还是同样的改法。
❗ 问题:登陆网页创建账户,提示请联系管理员。找到 https://github.com/overleaf/overleaf/wiki/Creating-and-managing-users 发现我用的是 legacy 的方法。后面也有解决方案,但是我没有继续往下走了。考虑到过时方法还可能出现别的问题,就换成使用 toolkit 了。
同学把 LaTeX 源码文件夹从 Windows 电脑上拷贝给我,但是无法编译,说是里面有几个字体找不到。我改了 fontspec
的几个设置,包括 \setmainfont
等,向其中用 Path=
选项添加了 fonts/
的路径(之前没有路径,找的是系统字体)。但是还是不能编译!
然后又慢慢排查,发现是 \maketitle
导致的不能编译,而且也是字体问题,只不过报错的位置变了,一时没看到。点进去看,cls 文件使用了 \arial
,而这个字体是这样定义的:
\DeclareRobustCommand{\arial}{\fontspec{Arial}}
虽然 cls 文件设置了文件夹中的 Arial 字体为主字体,但是没有将其声明为一个可以被引用的字体。但是我尝试添加字体的声明也不能成功:
\newfontfamily\arial[Path=extrafonts/]{Arial}