【问题标题】:Static vs. Dynamic Array C++静态与动态数组 C++
【发布时间】:2018-07-29 16:45:42
【问题描述】:

C++ 编译器的行为可能不同。由于可以使用以下方法声明 C++ 中的数组:

方法一:

int size;
cout << "Enter size of array: ";
cin >> size;

int x[size];  
for (int i = 0; i < size; i++)
{
    //cout << "x[" << i << "] = ";
    x[i] = i + 1;
}  

方法B

int size;
cout << "Enter size of array: ";
cin >> size;

int *x = new int[size];  
for (int i = 0; i < size; i++)
{
    //cout << "x[" << i << "] = ";
    x[i] = i + 1;
}

通过在运行时获取用户的输入,两者都可以正常工作。我知道,使用 B 方法,我们必须像 delete [] x 一样删除 x

  • 为什么要使用int *x = new int[size];,如果两者服务相同 目的?
  • 使用new 有什么好处?

下面是我正在测试的代码sn-p:

#include<iostream>
using namespace std;

int main()
{
    int size;
    cout << "Enter size of array: ";
    cin >> size;

    //int *x = new int[size];
    int x[size];

    for (int i = 0; i < size; i++)
    {
        //cout << "x[" << i << "] = ";
        x[i] = i + 1;
    }

    cout << endl << "Display" << endl;
    for (int i = 0; i < size; i++)
    {
        cout << "x[" << i << "] = " << x[i] << endl;
    }  
    return 0;  
}

【问题讨论】:

  • “方法 A”无效。 C++ 没有variable-length arrays。每当您想到“动态数组”时,您的下一个想法应该始终std::vector
  • @Malikx 那你肯定应该启用更多警告。
  • 方法 A 是 一些 编译器支持的编译器扩展 - 它不是标准 C++
  • @Malikx - 一个有效的 C++ 结构和一个接受它的编译器不是一回事。编译器可能会实现语言扩展或其中存在错误。
  • 因为没有使用-pedantic 标志编译...

标签: c++ arrays dynamic static


【解决方案1】:

C++ 标准没有定义方法 A,但在 ISO C99 中是允许的,并且 GCC 在 C++ 模式下也支持它。来自https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html

在 ISO C99 中允许使用可变长度自动数组,并作为 扩展 GCC 在 C90 模式和 C++ 中接受它们。这些数组是 像任何其他自动数组一样声明,但长度为 不是常量表达式。存储在点分配 当块作用域包含 声明退出。

我刚刚在这里找到了一些相关的讨论:Variable Length Arrays in C++14?

【讨论】:

【解决方案2】:

简单的答案是:堆栈空间有限。您可以期望能够在堆上分配 1GiB,但不能期望能够在堆栈上分配相同的数量。

第一个变体int x[size]; 使用堆栈。因此,如果size 很大,您可能会发现您的程序会因段错误而崩溃。通过简单地减少 CPU 的堆栈指针寄存器来进行分配。如果您将其减少太多,内核只会将您对堆栈内存的下一次访问视为越界访问,并终止您的进程。在实际被击中之前不可能检测到这种情况,或者以有序的方式从中恢复。内核只是在没有任何警告的情况下向您开枪。

第二个变体int* x = new int[size]; 使用堆。因此,只要有足够的可用 RAM 来支持分配,您就可以期望分配成功。 operator new() 会以有序的方式明确地向内核请求内存,而内核将要么遵从,要么以有序的方式发回这么多内存不可用的信号。在发生错误的情况下,operator new() 将继续抛出异常,您可以随意捕获和处理该异常。


旁白:
如果您的内核过度使用其内存(如任何现代 Linux),则保证在发生错误时会获得异常。当operator new() 向它请求内存而不实际提供任何内存时,内核只会回复“ok”,并且稍后可能会发现它无法履行其承诺。发生这种情况时,它将调用 OOM-killer(内存不足杀手),它会根据一些启发式方法来射击一些进程。所以,永远不要指望不会因为过多的内存消耗而被枪杀。

这实际上是一种能够实际使用所有可用内存的优化:一方面,许多程序实际上并没有使用它们分配的所有内存(例如分配一个大缓冲区,但只使用它的一部分)。另一方面,不可能知道哪些 COW(写时复制)映射页面实际上需要复制。内核不知道未来需要多少内存,它只知道当前是否有足够的内存。


TL;DR:
只有当你可以证明size 永远不会超过一个小的最大值时,才使用int x[size];。如果size 的数量级在 10 到 100 之间(并且类型本身并不是非常大),那就去吧。在所有其他情况下使用int* x = new[size];

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-31
    • 2019-06-02
    • 2016-05-28
    • 2014-07-21
    • 1970-01-01
    相关资源
    最近更新 更多