在结构体中初始化常量数组

3
致Stack Overflow会员,
我正在编写一个需要多个循环的模拟器(有时超过100万次),每个循环都涉及到大量计算。因此,循环节省10毫秒可以导致节省超过160分钟的计算时间。因此,我正在努力进行所有可能的代码优化。之前,我将所有系统参数从文件中导入到向量中。后来我意识到:
  1. 调用常量int / double / ...比调用常规int / double / ...更快
  2. 使用数组比使用向量更快
  3. 我不需要std :: string的全部功能,并且可以制作一个简单的仿制版本来使用
最初,我天真地认为我可以将std :: vector 转换为std :: vector 。由于我也在尝试使用Linux跨平台,我发现Visual Studio Express编译器忽略了无法像那样声明const的事实(而Linux则抛出了大量错误)。
我决定在初始化的结构体中使用常量数组;但是,我无法找到正确初始化它的方法。(我遇到的大部分/所有帮助论坛都说要声明static const int *并将其作为全局变量进行初始化,但我认为这对我所需的目的无效)。我终于开发出了这个最终解决方案,但我相信我犯了一个“禁忌”,因为我最终使用指针声明常量。它可以编译和运行而没有错误,所以我想知道,使用指针初始化常量数组是否有问题?如果有的话,还有什么其他的方法可以做到这一点吗?(我理解用这种方式获取所有数据可能会更慢,但在时间重要的部分,调用应该更快...我想)
#include <stdio.h>
#include <malloc.h>
#include <conio.h>

#if defined(_WIN32) || defined(_WIN64)
#define gsize _msize
#else
#define gsize malloc_usable_size
#endif

struct testy{
    const int *i;
    const double *d;
    testy(){
        i=(const int *)malloc(0);
        d=(const double *)malloc(0);
    }
};

inline const int* getDat(const int* dst, int* src){
    dst=(const int*)realloc((void *)dst,gsize((void *)src)); // Allocate enough memory to hold the data
    return src;
}

inline const double* getDat(const double* dst, double* src){
    dst=(const double*)realloc((void *)dst,gsize((void *)src)); // Allocate enough memory to hold the data
    return src;
}

int main(){
    testy data;
    int *tmp_i = (int *)malloc(0);
    double *tmp_d = (double *)malloc(0);

    for(int i=0;i<3;i++){ // load empty array with what i want
        tmp_i=(int*)realloc((void *)tmp_i,gsize((void *)tmp_i)+1*sizeof(int)); // Increase size by one
        tmp_i[i]=i;
    }
    for(int i=0;i<3;i++){ // load empty array with what i want
        tmp_d=(double*)realloc((void *)tmp_d,gsize((void *)tmp_d)+1*sizeof(double)); // Increase size by one
        tmp_d[i]=i;
    }

    data.i=getDat(data.i,tmp_i);
    data.d=getDat(data.d,tmp_d);

    printf("\nIntegers\n");
    for(int i=0;i<(gsize((void *)data.i)/sizeof(int));i++)
        printf("%d\t",data.i[i]);

    printf("\nDoubles\n");
    for(int i=0;i<(gsize((void *)data.d)/sizeof(double));i++)
        printf("%lg\t",data.d[i]);

    free(tmp_i); free(tmp_d);
    _getch();
    return 0;
}

我从这段代码中删除了仿冒字符串及其使用,因为声明该数组存在一些问题,而且我不想在这里问更多的问题。


如果你想要速度,最好避免使用堆内存。 - aaronman
使用堆内存没有问题 - 通常比糖浆慢的是分配和释放。理想情况下,在开始迭代之前从系统分配器获取所需的所有内存。 - Casey
如果我不在初始化期间关心速度,但是在访问数据时关心速度,那么动态分配还重要吗?我认为一旦完成了所有的分配(并且假设我之后不会重新分配,这是不应该的),动态初始化变量的行为就像常规初始化变量一样。 - hherbol
@Casey 实际上堆仍然可能会更慢,但是我更多的是开个玩笑,因为 OP 已经假设 vector 对他的目的太慢了,而同时使用另一个 SO 经常批评的特性。 - aaronman
@Casey:“栈更快,因为它的访问模式使得从中分配和释放内存变得很容易(指针/整数只需递增或递减),而堆则在分配或释放时涉及更复杂的簿记。此外,栈中的每个字节往往会被频繁重用,这意味着它往往会映射到处理器的缓存中,使其非常快。” - aaronman
显示剩余4条评论
1个回答

3
  1. 移除realloc。它很昂贵,并且会导致内存碎片化。
  2. const 不会有任何区别 - 最终您必须访问内存,const 只是确保您不会更改不应更改的内容。
  3. 如果值是不可变的,请将像 (gsize((void *)data.d)/sizeof(double) 这样的东西放在 for 循环之外。这可以避免每次循环都进行一次函数调用。
  4. 使内存高速缓存正常工作。即按顺序访问内存中的数据。从内存传输到处理器的数据可以轻松地进行预取。
  5. 对于任何复杂操作(您未展示),请使用一些代数方法简化方程式。如可能,请尽可能使用整数而不是 double,这取决于问题空间。

1
到目前为止,我同意2->5;然而,在1中,如果我要删除realloc,那么我该如何调整数组大小呢?我需要让程序动态创建可以容纳文件中所有数据的数组。而且这些文件会随着时间的推移而改变(添加/删除值)。 - hherbol
编译器可以将const作为更积极优化的提示。 - jxh
@hherbol - 有一个上限吗?减少realloc的数量。如果使用C++ vector实现这个功能。正如你所说,你可能已经有一个很好的上限来开始第一步。甚至可以只使用一个带有大数组的堆栈(在安全关键系统中使用,防止程序员使用堆分配)。 - Ed Heal
@jxh - 我认为你在考虑使用 const 而不是 #define - Ed Heal
@Ed Heal - 哦,等等!关于您的第二个问题,我还有一个最后的问题。这是否意味着我可以通过指向它们的内存的指针来初始化常量?或者您是说速度优势不存在? - hherbol
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接