【问题标题】:Declaring vector as global variable in C++在 C++ 中将向量声明为全局变量
【发布时间】:2011-11-25 08:01:31
【问题描述】:

在 C++ 中将向量声明为全局是否是一种好习惯?

这就是我所做的。

#include <vector>
std::vector<int> vec;

我的程序编译成功,但我不确定这是否会导致运行时 特定情况下的错误。根据我的理解,全局变量的内存将在编译时分配,编译器可能会保留有限的内存,这个向量可以扩展。达到此限制后,正在写入的内容可能会占用另一个变量使用的内存。

请指教。

【问题讨论】:

  • 将任何东西声明为全局变量通常不是一个好习惯。
  • 是否可以在主函数中使用0 重新初始化全局数组或向量的所有元素? (不使用 for loop/ )我正在寻找一种有效或直接的方式。

标签: c++ vector heap-memory


【解决方案1】:

只有向量元数据的空间会被分配到全局变量的区域。向量内容仍将动态分配(构造函数和析构函数对全局变量正常运行)。

自动向量变量也是同样的情况,比如:

int main(void)
{
    std::vector<int> v;
    return 0;
}

自动变量可用的堆栈空间是有限的,但向量内容不会使用这个空间,只有少数指针和计数器。

【讨论】:

  • 关于堆栈空间的限制 (stackoverflow.com/questions/1825964/…) 请注意,我很惊讶使用页面错误(例如虚拟内存交换)按需分配额外的堆栈页面是不正常的——堆栈和堆可以想象,可以从虚拟地址空间的相反极端一起成长
  • @spraff:堆栈限制完全不是重点——向量内容不与向量成员连续存储,它们存储在动态分配的区域中。此外,曾几何时,堆栈和堆确实彼此相向而行。然后发明了多线程,并且需要在单个地址空间内建立多个堆栈。
【解决方案2】:

根据我的理解,全局变量的内存会在编译时分配,编译器可能会预留有限的内存供这个向量扩展。

这是错误的理解。

内存在编译时没有分配。内存在程序启动 时分配,然后在程序期间 分配,具体取决于变量的存储 类型。并且当程序关闭时,它所使用的所有内存无论如何都会返回给操作系统。

达到此限制后,正在写入的内容可能会占用另一个变量使用的内存。

没有。 std::vector&lt;int&gt; 的对象永远不会吃掉另一个变量使用的内存

现在回到你的主要问题,

在 C++ 中将向量声明为全局是一种好习惯吗?

没有。避免使用全局变量,无论其类型如何。

【讨论】:

  • 如果要避免全局变量 - 如何在 C++ 中进行缓存?
【解决方案3】:

全局变量通常是不好的做法。正如您所说,它们不会“吞噬”另一个变量的内存,但是,作为程序员,您很容易搞砸一些事情。例如,程序中的所有内容都可以访问此向量,因此所有内容都可以访问和修改它。你可能想要也可能不想要这个,但很可能你不想要这个。

至于内存分配,添加到向量中的对象仍然会在运行时添加(因为它们在编译时不存在!)。内存也永远不会在编译时分配。您的程序中有签名在运行时分配此内存。想想看……如果程序在编译时分配内存,你真的不能在其他机器上运行它们吗?内存将分配在您的机器上,而不是其他机器上。因此,内存必须在运行时分配。

【讨论】:

  • 分配是划分更大区域的过程。这些部分是在运行时从系统内存分配的,全局变量是在编译时从该部分分配的。 (如果我们想更进一步,我们可以讨论在购买计算机时将内存模块分配给特定的个人计算机。)我们通常不会说批量复制“分配”块的一部分。
  • @Ben Voigt 你有这方面的任何文件吗?我的兴趣是低级编码等,所以我想进一步了解它!
  • 你的意思是definition?考虑休眠过程(也称为挂起到磁盘)可能会有所帮助。当您恢复计算机时,内存的全部内容会从休眠发生时的状态映像中批量复制。您会说内存内容被加载或复制等。但是您不会说在恢复期间进行了 4 亿次分配。包含全局变量的部分也是如此,它在构建时分配,然后在运行时复制到内存中,保持现有结构。
  • 我明白了,所以它留出了这些全局变量将出现在内存中的哪个位置以及它们占用了多少内存,然后在运行时用于实际初始化全局变量。
  • 对。现在我们进入全局常量和全局变量之间的区别,全局常量(通常称为.cdata)是从磁盘复制到内存中的。对于全局变量(通常是.data),加载器只需为所有变量组合获取足够大的内存块并将整个内容归零。在任何情况下,布局都是在编译时完全确定的。大块复制进去后,运行时库将开始在单个对象上运行构造函数。
【解决方案4】:

您的程序在编译时不分配任何东西 - 我认为您的意思是运行时。

Vector 在堆上分配它持有的东西 (vec.size() * sizeof(/* 你持有的东西*/)) - 它在分配的位置持有 sizeof(std::vector)。全局变量可以存储在任何地方,这取决于实现。

【讨论】:

  • 在大多数系统上都有一个“初始化数据”部分,其中存储了所有全局变量,该部分的大小和其中变量的位置在构建期间设置(由链接器,而不是编译器,但绝对不是运行时)
  • @Ben Voigt AFAIK,全局变量在加载时分配,并在运行时初始化。
【解决方案5】:

好吧,vec 是一个全局变量,所以它的内存大概是从数据段分配的。但是, vec 内容的内存取决于分配器。默认情况下,我认为内容的内存是从堆中分配的。

【讨论】:

    【解决方案6】:

    我的程序编译成功,但我不确定这是否可以 在某些情况下会导致运行时错误。

    这样做是安全的; vec 变量的存储空间将被静态分配,它的默认构造函数将在某个时候被调用(确切地说,当在整个程序的上下文中没有严格定义时,因为跨翻译单元的初始化顺序没有严格定义)。

    并且编译器可能会保留有限的内存量 矢量可以扩展。达到此限制后,正在写入的内容可以 吃掉另一个变量使用的内存。

    向量本身在堆上分配其存储空间,因此如果将向量实例化为局部变量,则不会对其扩展施加任何限制:您基本上会受到内存量的限制您可以在向量需要重新分配其内部存储的时间点连续分配。

    综上所述,虽然这样做是安全的,但不一定是好的做法;它属于所有其他全局变量或全局可访问的存储位的域,这可能是一个有争议的主题。一般来说,我建议最好避免使用全局变量。虽然在某些情况下它可能是可以接受的,但全局访问与您控制对变量的访问并对其强制执行不变量以及它控制或暗示的状态的能力背道而驰。随着代码库的扩展,这可能会导致系统难以维护,因为这些访问路径没有明确说明。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多