C++ 运行时检查失败#4-此函数保留的#alloca内存周围的堆栈区域已损坏?

C++ 运行时检查失败#4-此函数保留的#alloca内存周围的堆栈区域已损坏?,c++,stack,runtime-error,alloca,C++,Stack,Runtime Error,Alloca,我使用Visual C++ 2019,STDC++ + 14和STDC++ + 17都产生相同的错误。 这段代码有什么问题?我假设这只是一段示例代码,因为如果您只是想打印数字0..n,那么您完全没有理由使用数组:-) 至于您的实际问题,alloca函数,如malloc,分配了大量字节。如果将其视为有许多int值(几乎可以肯定大于一个字节),则不会有好的结果。这在对话框中得到了确认,其中大小为10,但每个数组元素占用4个: Run-Time Check Failure #4 - Stack ar

我使用Visual C++ 2019,STDC++ + 14和STDC++ + 17都产生相同的错误。
这段代码有什么问题?

我假设这只是一段示例代码,因为如果您只是想打印数字
0..n
,那么您完全没有理由使用数组:-)


至于您的实际问题,
alloca
函数,如
malloc
,分配了大量字节。如果将其视为有许多
int
值(几乎可以肯定大于一个字节),则不会有好的结果。这在对话框中得到了确认,其中大小为10,但每个数组元素占用4个:

Run-Time Check Failure #4 - Stack area around _alloca memory reserved by this function is corrupted

在任何情况下,我都会避免alloca,因为:

  • 这真的不标准;及
  • 如果它不能分配空间,而不是像
    new
    那样引发异常,那么它就会有一个令人讨厌的坏习惯
  • 关于最后一点,各国(我强调):

    函数的作用是:返回一个指向所分配空间开头的指针如果分配导致堆栈溢出,则程序行为未定义。

    如果你想要一些你不用担心自己去分配它的东西,现代C++有智能指针,你可以使用类似的:

    Size: 10
    Data: <> 00 00 00 00 01 00 00 00 02 00
             \_________/ \_________/ \____
                arr[0]      arr[1]      ar
    
    int *arr = (int*) alloca(n * sizeof(*arr)); // n ints, not bytes.
    
    另外,你会注意到我也改为使用
    size\u t
    而不是
    int
    作为大小和索引-我认为这更适合。当然,这是使用堆而不是堆栈,但根据前面关于
    alloca
    的评论,这是更安全的方法

    如果您保证对尺寸进行一定限制,例如:

    #include <iostream>
    #include <memory>
    
    void print_vals(size_t n) {
        std::unique_ptr<int[]> arr(new int[n]);
    
        for (size_t i = 0; i < n; i++)
            arr[i] = static_cast<int>(i);
        for (size_t i = 0; i < n; i++)
            std::cout << arr[i] << ' ';
        std::cout << '\n';
    }
    
    int main() {
        print_vals(5);
        print_vals(10);
    }
    
    但这实际上并不能保证它的安全性,如果你打算这样做,你也可以使用固定的缓冲区,因为你知道最大大小:

    void print_vals(size_t n) {
        if (n >= 100) {
            doSomethingIntelligent();
            return;
        }
        int *arr = (int *)alloca(n * sizeof(*arr));
    
        ...
    }
    

    我想提出的另一个解决方案是:如果您的目的是尽可能提高效率,那么您可以使用混合方法。我的意思是,在低于一定大小时使用本地缓冲区,并仅在需要时分配内存:

    void print_vals(size_t n) {
        int arr[100];
        if (n >= sizeof(arr) / sizeof(*arr)) {
            doSomethingIntelligent();
            return;
        }
    
        ...
    }
    
    void打印值(大小){
    //默认使用本地缓冲区。
    int localBuff[100];
    int*arr=localBuff;
    //如果需要更多空间,请分配自动释放智能指针。
    std::唯一的\u ptr allocBuff;
    如果(n>=sizeof(localBuff)/sizeof(*localBuff)){
    allocBuff.reset(新整数[n]);
    arr=allocBuff.get();
    }
    //这里,arr指向一个足够大的缓冲区。
    ...
    
    函数的参数是要分配的字节,因此元素的大小必须乘以元素的数量

    可以这样做:

    void print_vals(size_t n) {
        // Default to using local buffer.
    
        int localBuff[100];
        int *arr = localBuff;
    
        // If more space needed, allocate  an auto-freeing smart pointer.
    
        std::unique_ptr<int[]> allocBuff;
        if (n >= sizeof(localBuff) / sizeof(*localBuff)) {
            allocBuff.reset(new int[n]);
            arr = allocBuff.get();
        }
    
        // Here, arr points to to a big-enough buffer.
    
        ...
    

    你为什么在C++中使用原始的C风格记忆管理?有什么理由吗?这个代码大声地发出一个简单的<代码> STD::VECor < /C>ῥεῖ 因为Visual C++不允许VLA。这回答了你的问题吗?@ StasExchange 123 HMM,好。这似乎是有意义的。否则你需要实现你自己的描述:谢谢。我不知道我是怎么错过的……但是为什么它打印正确的值tho?@ StasExchange 123,你做的是未定义的行为。这意味着UND。定义为“它甚至可以工作,至少在一段时间内”:-)可能发生的情况是,它在分配的空间之外自由地写入和读取内存,但是,当要退出函数时,发生了损坏。实际上,你很幸运它捕获了它,而不是使用堆栈上可能损坏的返回值返回到
    main
    。我们不得不使用EcTimes的东西,像它几乎肯定大于一个字节,我们不能只是让所有的512位,并用它做?@ PaxDabLo我使用它,因为VLAS是不允许在VisualC++中。还有其他的方式吗?@ StAcExchange 123:我已经添加了一些其他选项供您考虑。
    void print_vals(size_t n) {
        int arr[100];
        if (n >= sizeof(arr) / sizeof(*arr)) {
            doSomethingIntelligent();
            return;
        }
    
        ...
    }
    
    void print_vals(size_t n) {
        // Default to using local buffer.
    
        int localBuff[100];
        int *arr = localBuff;
    
        // If more space needed, allocate  an auto-freeing smart pointer.
    
        std::unique_ptr<int[]> allocBuff;
        if (n >= sizeof(localBuff) / sizeof(*localBuff)) {
            allocBuff.reset(new int[n]);
            arr = allocBuff.get();
        }
    
        // Here, arr points to to a big-enough buffer.
    
        ...
    
    int *arr = (int *)alloca(sizeof(*arr) * n);