为什么这段代码编译后的文件这么大?

问题描述 投票:0回答:1

我最近写了以下代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <array>
#include <set>
#include <map>
#include <unordered_map>
using namespace std;

using ll = long long;

constexpr int N = 5e4 + 5;
constexpr ll INF = (ll)1e12;

array<basic_string<int>, N> c, tc;
int n, m;

array<basic_string<ll>, N> sl, sr, sm;
array<ll, N> val, sv;
ll ans;

int main()
{
    return 0;
}

main函数里面的代码并不重要,所以我省略了。

当我尝试在 Windows 中使用选项 -std=c++20 在“gcc 版本 14.2.0(Rev1,由 MSYS2 项目构建)”中编译它时。它编译了 10 多秒,并获得了至少 8 MB 的可执行文件,这比大多数其他代码要大得多。但如果我使用c++17或更低版本,它可以正常编译。而如果我把数组改成C类型数组,就可以正常编译了。另外,如果我使用“gcc version 12.2.0(x86_64-posix-seh-rev1,由 MinGW-W64 项目构建)”或 clang,它也可以工作。

我们相信这与 C++20 有关,但我们并不确切知道。那么有什么问题吗?谢谢。

我觉得编译结果不应该是这样的,不应该需要那么多时间和内存。

c++ arrays compilation
1个回答
0
投票

这个问题是多种因素综合作用的:

    C++20 中的数组和模板实例化:constexpr 数组对象(例如 array
  1. )中使用的 std::array 和 std::basic_string 可以触发繁重的模板实例化,特别是对于 N 的大 constexpr 值(在此案例,50005)。 C++20 为模板实例化增加了额外的复杂性,因为它改进了 constexpr 评估和类型推导,这可能会导致编译期间产生更多内部计算。
  2. GCC 版本特定行为:GCC 14.2.0 和旧版本(例如 GCC 12.2.0)之间编译时间和可执行文件大小的差异表明较新版本的 GCC 中引入了回归或低效率。每个编译器版本对模板密集型代码的优化都不同。 GCC 14.2.0 在优化 std::array 和 std::basic_string 组合的实例化方面可能会较慢,或者可能会生成效率较低的中间代码。
  3. 大型静态对象的影响:包含 basic_string 的大型 std::array 对象可能会导致编译的二进制文件占用大量内存。当 N = 50005 时,数组是静态分配的,并且它们的大小根据它们所持有的类型而倍增。特别是, std::basic_string 由于其内部结构而增加了开销。
  4. C++20 的编译器优化:C++20 引入了更丰富的 constexpr 支持并对标准库进行了更改。例如,某些算法和数据结构现在与 constexpr 兼容,但这可能会增加编译时复杂性,因为编译器会预先执行更多分析和代码生成。
示例

数组

c, tc;

向量

c(N), tc(N);

说明

    减少 N 以进行调试:使用较小的 N 值进行测试,以隔离较大的 constexpr 大小是否是根本原因。
  1. 避免大量模板嵌套:考虑使用更简单的类型或避免嵌套 std::array
  2. 结构。例如,您可以将 basic_string 替换为向量或更简单的结构。
  3. 切换到旧版 GCC 或 Clang:如果可能,请使用能够高效编译代码的编译器版本。对于模板较多的代码,Clang 通常具有更好的性能。
  4. 报告问题:由于此行为特定于带有 C++20 的 GCC 14.2.0,因此您可能需要向 GCC 开发团队报告此问题。这可能是性能下降或效率低下。
  5. 替代分配:使用动态内存分配(std::vector 而不是 std::array)来减少编译期间大型静态分配的影响。
© www.soinside.com 2019 - 2024. All rights reserved.