C++程序出现堆栈溢出错误

4

我有一个复杂的类,想要创建一个二维复数数组。以下是部分代码:

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];
}

所以,Complex G[HEIGHT][WIDTH] 这一行是导致问题的原因,你有什么想法吗?


3
假设一个双精度浮点数需要8个字节,那么仅用于变量G的栈空间就需要1MB,而这通常已经接近栈空间的极限。 - chris
因为您正在使用65536个“Complex”对象溢出堆栈。这真的不是一个...复杂...的事情去理解。 - ta.speot.is
最好不要在堆栈上分配大型数组 - 使用malloc - 并且可能创建一个访问函数作为类的一部分,以便保持索引简单。 - Floris
@Floris,s/malloc/vector/. - chris
尝试使用静态变量。这将把它放入静态数据区,避免浪费宝贵的堆栈空间...与malloc不同,编译器仍然知道它在编译时的位置 :) - jheriko
@chris - 谢谢。混淆了我的语言... - Floris
2个回答

8

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

Complex G[HEIGHT][WIDTH];

默认情况下堆栈大小约为1MB,您可以使用/F进行修改,文档中指出(我的强调):

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

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

据我所知,Visual Studio实际上具有较小的默认堆栈大小:

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

1
有什么想法吗?
一些编译器将堆栈大小默认设置为1MB。您正在分配65536个占用2 * sizeof(double)内存的Complex对象。假设double为8个字节(此信息由实现定义),则您实际上正在尝试分配16 * 65536个字节(不考虑可能的填充),这会导致溢出。
另一种选择是使用包装器进行动态分配,该包装器模拟二维数组索引,类似于以下内容:
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; }

这是无用的。不要重新初始化即将在离开作用域时被销毁的内存。


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