【问题标题】:stack overflow error in C++ programC++程序中的堆栈溢出错误
【发布时间】:2013-12-12 14:20:53
【问题描述】:

所以我有这个复杂的类,我想要一个二维复数数组,这是代码的一部分,而不是所有代码

class Complex {
public:
    /* construction/destruction */
    Complex(double r, double i)     { this->r = r; this->i = i; }
    Complex()                       { r=0.0; i=0.0; }
    ~Complex()                      { r=0.0; i=0.0; }
        /* operations */
    Complex operator+(Complex &c)   { return Complex( r+c.r, i+c.i ); }
        double r, i;
};

int main()
{
const int HEIGHT = 256;
const int WIDTH = 256;
Complex G[HEIGHT][WIDTH];
}

所以线复杂 G[HEIGHT][WIDTH];是导致问题的线路,知道为什么吗?

【问题讨论】:

  • 假设一个 8 字节双精度,这对于 G 单独来说就是 1MB 的堆栈存储空间,这通常是总体限制。
  • 因为您的堆栈溢出了 65536 个 Complex 对象。这真的不是一个……复杂的……要理解的东西。
  • 最好不要在堆栈上分配大数组 - 使用malloc - 并且可能创建一个访问函数作为类的一部分以保持索引简单。
  • @Floris, s/malloc/vector/.
  • 尝试静态。这将其放入静态数据区域并避免浪费宝贵的堆栈......与 malloc 不同,编译器在编译时仍然知道它在哪里 :)

标签: c++ class visual-c++ pointers


【解决方案1】:

Visual Studio 默认为 1MB 堆栈大小,如下所示:

Complex G[HEIGHT][WIDTH];

大约只有 1MB,您可以使用 /F 进行修改,文档显示(强调我的):

如果没有此选项,堆栈大小默认为 1 MB。 number 参数可以是十进制或 C 语言表示法。该参数的范围可以从 1 到链接器接受的最大堆栈大小。链接器将指定的值向上舍入到最接近的 4 个字节。 /F 和数字之间的空格是可选的。

最明显的替代方法是通过 newstd::vector 使用动态内存分配。

Visual Studio 据我所知,实际上有 one of the smaller default 堆栈大小:

platform    default size       
=====================================
SunOS/Solaris  8192K bytes
Linux          8192K bytes
Windows        1024K bytes
cygwin         2048K bytes
Mac OS X       8192K bytes

【讨论】:

    【解决方案2】:

    知道为什么吗?

    一些编译器默认堆栈大小为 1MB。您正在分配 65536 个 Complex 对象,每个对象占用 2 * sizeof(double) 内存。假设 double 为 8 字节(此信息由实现定义),您实际上是在尝试分配 16 * 65536 字节(不考虑可能的填充),即 1048576 字节,这会导致溢出。

    另一种方法是使用带有包装器的动态分配,它模拟二维数组索引,如下所示:

    template<std::size_t A, std::size_t B>
    class G {
    private:
        std::unique_ptr<Complex[]> mem;
    public:
        G() : mem(new Complex[A * B]) {}
        Complex& operator()(std::size_t a, std::size_t b) {
            return mem[a * B + b];
        }
        Complex  operator()(std::size_t a, std::size_t b) const {
            return mem[a * B + b];
        }
    };
    

    那么你的程序就变成了:

    int main(int, char*[]) {
        G<256, 256> g;
        g(0, 0) = ...;
    }
    

    当然,您可以将包装器 G 概括为带有模板的泛型类型,但这超出了此答案的范围。


    顺便说一句,你的析构函数:

    ~Complex() { r=0.0; i=0.0; }
    

    没用。不要重新初始化离开作用域时无论如何都会被销毁的内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-17
      • 2014-04-12
      • 2011-01-19
      • 2016-11-11
      • 1970-01-01
      • 2010-11-05
      • 2013-06-06
      • 2023-03-11
      相关资源
      最近更新 更多