小编sh-*_*sh-的帖子

C++虚函数:链接器是否可以删除未调用的虚函数表中的条目?

这个问题是一种消除未使用的虚函数的后续问题,对我的兴趣不够深入.

问题:在定义具有虚函数的类时,编译器为虚函数表分配存储,并存储指向表中函数的指针.这会导致链接器保留这些函数的代码,无论它们是否被调用.即使编译器优化设置要求消除死代码,这也可能导致大量死代码保留在可执行文件中.

现在,如果在可执行文件中没有任何地方存在特定虚函数的调用(或者换句话说,访问虚函数表的相应槽),则可以从虚函数表中省略相应的函数指针,并且链接器将删除函数的代码,可能会进一步遗漏其他未引用的代码.

显然,这不能由编译器完成,因为它只在链接时变得清楚是否调用了特定的虚函数(假设静态链接 - 很明显它不能用动态链接完成).我对链接器不够熟悉,以便判断编译器是否能够以链接器可以选择性地忽略表中各个未使用的条目的方式发出虚函数表.

基本上,我的思路是这样的:虚函数表中的函数指针是对函数的引用,链接器使用该函数来确定函数的代码需要保留在可执行文件中.以类似的方式,虚函数调用是对从其虚函数被调用的类派生的所有虚函数表中的特定槽的引用.这种引用是否可以通过这样一种方式传递给链接器:当它没有引用时,它可以忽略虚函数表槽?

请注意,当编译器可以在编译时确定调用目标时,这与使用直接调用替换虚函数调用不同.我知道一些编译器可以做到这一点,但这是一个不同的情况,因为函数实际上被调用,并且它是被删除的虚函数调度的开销.在我的情况下,我希望删除未调用的函数的整个代码.

如果我可以控制所有类定义,我可以手动删除所有未调用的虚函数.但是在使用库时这是不现实的.

这可以通过"链接时间优化"或"整个程序优化"来完成吗?是否有成功的编译器?

c++ linker dead-code vtable compiler-optimization

11
推荐指数
1
解决办法
879
查看次数

C/C++ 中高效的防溢出算术平均值

两个无符号整数的算术平均值定义为:

mean = (a+b)/2
Run Code Online (Sandbox Code Playgroud)

直接在 C/C++ 中实现可能会溢出并产生错误的结果。正确的实现可以避免这种情况。一种编码方式可能是:

mean = a/2 + b/2 + (a%2 + b%2)/2
Run Code Online (Sandbox Code Playgroud)

但这会使用典型的编译器生成相当多的代码。在汇编程序中,这通常可以更有效地完成。例如,x86 可以通过以下方式执行此操作(汇编器伪代码,我希望您明白这一点):

ADD a,b   ; addition, leaving the overflow condition in the carry bit
RCR a,1   ; rotate right through carry, effectively a division by 2
Run Code Online (Sandbox Code Playgroud)

在这两条指令之后,结果位于 中a,除法的余数位于进位位中。如果需要正确的舍入,第三ADC条指令必须将进位添加到结果中。

请注意,使用了 RCR 指令,该指令通过进位来循环寄存器。在我们的例子中,它是旋转一个位置,以便前一个进位成为寄存器中的最高有效位,并且新的进位保存寄存器中的前一个LSB​​。看来 MSVC 甚至没有提供该指令的内在函数。

是否存在已知的 C/C++ 模式可以被优化编译器识别,从而生成如此高效的代码?或者,更一般地说,是否有一种合理的方法如何在 C/C++ 源代码级别进行编程,以便编译器使用进位位来优化生成的代码?

编辑:

1 小时的讲座std::midpointhttps://www.youtube.com/watch ?v=sBtAGxBh-XI

哇!

EDIT2:微软博客上的精彩讨论

c c++ optimization intrinsics compiler-optimization

10
推荐指数
2
解决办法
479
查看次数

如何使用 FetchContent 将模块化 boost 构建正确集成到我的 CMake 项目中?

CMake FetchContent 是管理构建依赖项的好方法,通过将依赖项集成到您的构建中并从源代码以及您自己的源代码构建它。

我也想用 Boost 来做到这一点。CMake 对 Boost 的支持正在稳步改善,这一事实令我深受鼓舞。

当然,由于 Boost 是一个大包,并且很少在项目中使用所有 Boost 库,因此将整个 Boost 源拉入自己的构建中会相当浪费。考虑到 Boost 项目的模块化,使用 git 子模块,仅获取实际使用的库的源代码会更加智能和高效,并且 FetchContent 通过其 GIT_SUBMODULES 选项支持这一点。

然而,这似乎并不能满足 Boost 库之间的依赖关系。我需要手动处理这个问题,还是有更智能的解决方案?

此外,在这种情况下如何控制安装?许多 Boost 库都是仅包含头文件的,我不希望在安装中包含头文件,因为我只将它们用于我的构建。有没有办法告诉 CMake 我不想从使用 FetchContent 获取的内容中安装任何内容?

我读过 Craig Scott 的书,当然还有 CMake 文档,但是关于此类问题的信息并不多。

但也许我正在尝试一些我不应该做的事情。其他人是否尝试过此操作,并且可以向我展示它是如何正确完成的?

c++ boost cmake dependency-management

9
推荐指数
1
解决办法
1791
查看次数

std::chrono 和缺少 (?) 对负闰秒的支持

C++20 添加了时区支持std::chrono,其中包括闰秒。然而,似乎只支持闰秒插入,而不支持闰秒删除,即负闰秒。(诚​​然,自 1972 年以来,只有正闰秒;但在过去几年中,这种趋势似乎已经逆转,未来几年似乎有可能出现负闰秒。)

从类的描述方式中可以明显看出这一点std::chrono::leap_second- 无法区分正闰秒和负闰秒。

是否知道为什么std::chrono不支持这种可能性?这是一种优化,还是某种错误?或者它已经支持但我错过了一些东西?

注意:MSVC 实现似乎有一个允许负闰秒的非标准功能。

c++ c++-chrono leap-second c++20

7
推荐指数
1
解决办法
415
查看次数

如何在现代CMake中正确处理_WIN32_WINNT和WINVER

_WIN32_WINNT我想知道WINVERCMake 项目的“现代”(阅读:基于属性)方式是什么。

我想解决的问题是如何将版本设置为我的项目的任何库或子组件所需的最高值。例如,如果我的项目代码本身需要WINVER至少为 0x0601 (Windows 7),但它使用的库 A 至少需要 0x0603 (Windows 8.1) 和库 B 至少需要 0x0A00 (Windows 10),那么很明显我的整体产品需要其中最高的。

如果我只是将适当的设置定义为target_compile_definitions,我最终可能会在命令行上多次使用相同的宏定义,最后一个优先,这可能是错误的。

如何安排自动获取最高版本?

我试图找到这个问题的其他答案,但它们似乎相当古老,因此似乎并不反映现代实践。

windows cmake

6
推荐指数
0
解决办法
829
查看次数

std::shared_ptr<std::string const> 可以作为引用计数不可变字符串的有效实现吗?

理想情况下,不可变字符串类只需要为每个字符串分配一次内存。甚至引用计数也可以存储在保存字符串本身的同一块内存中。

string和的简单实现shared_ptr将为 分配三个不同的内存shared_ptr<string const>

  • 字符串缓冲区的内存
  • 字符串对象的内存
  • 引用计数的内存

现在,我知道在使用 时std::make_shared(),智能实现可以将后两者合并为一个分配。但这仍然会留下两个分配。

当您知道字符串是不可变的时,字符串缓冲区将不会被重新分配,因此应该可以将其与字符串对象集成,只留下一次分配。

我知道某些字符串实现已经对短字符串使用了此类优化,但我正在寻找一个无论字符串长度如何都可以执行此操作的实现。

我的问题是:我的推理合理吗?实施实际上是否允许并且能够做到这一点?我可以合理地期望一个高质量的标准库来实现这种优化吗?您知道当代图书馆的实现可以做到这一点吗?

或者这是我必须自己实现的事情?

c++ string std immutability

5
推荐指数
1
解决办法
5178
查看次数