如果存在堆栈溢出的可能性,为什么要使用堆栈?

时间:2015-05-09 23:39:14

标签: c++

让我们说我有一个代表我申请的课程:(很抱歉没有同时显示h和cpp,但这只是为了简洁)

class App
{
    App()
    {
        window( new Window() );
        window->Height( 400 );
        window->Width( 400 );
        window->Title( "Bob" );
    }

    unique_ptr<Window> window;
    // ... Possibly more variables
}

class Window
{
public:

    // Get
    int Height(){ ... };
    int Width(){ ... };
    string Title(){ ... };    

    // Set
    void Height( int height ){ ... };
    void Width( int width ){ ... };
    void Title( string title ){ ... };

private:

    int height;
    int width;
    string title;

    // ... Possibly more variables

}
App app;

int main()
{

}

我的int类中的所有stringWindow类型都在堆栈中声明。在某些时候,如果我继续在这些类中的堆栈中声明内容,我将最终导致堆栈溢出......对吗?

所以我的问题是 ...为什么你要在堆栈上声明东西?我不应该这样做吗?

// ...
App()
{
    window( new Window() );
    window->Height( unique_ptr<int>( new int( 400 ) ) );
    window->Width( unique_ptr<int>( new int( 400 ) ));
    window->Title( unique_ptr<string>( new string( "Bob" ) ) );
}
// ...
private:

    unique_ptr<int> height;
    unique_ptr<int> width;
    unique_ptr<string> title;

...

不同之处在于整数和字符串的内存现在在堆上声明。

3 个答案:

答案 0 :(得分:5)

Why would you ever want to declare stuff on the stack?

我能想到的2个理由:

  1. 性能:堆栈非常快。我记得在某个地方听到这个,但提高性能的最佳方法是避免前往堆。

  2. 复杂性:使用动态内存会产生更多复杂性,因为您必须考虑内存管理。使用堆栈比使用堆更简单。使用动态内存会增加程序的复杂性。

答案 1 :(得分:0)

即使您将窗口声明为unique_ptr<Window> window,您也会在堆栈中声明某些内容。在这种情况下,unique_ptr<Window>的实例。在堆栈上声明int和其他小原语或结构是很好的,因为即使你在堆上声明它们,你也需要在堆栈上声明指向它们的指针。你总是需要在堆栈中保存一个指向堆上位置的指针,这样如果你的数据类型小于指针(或接近相同的大小),那么将它保存在堆栈上会更有效率而不是堆。这是因为访问堆栈的速度比堆快,因此在存储堆(指针和对象本身)时必须存储两个对象,而在存储堆栈时只需存储一个。

std::string为例。它可能在内部保存一个指向存储原始数据的堆上位置的指针。所以在堆栈上你持有一个指针,并在堆上原始数据(字符串文字有点不同,所以一般的想法仍然存在)。

通常,在unique_ptr中存储int几乎没有意义,除非它是数组的地址。如果你只是将它声明为原始int,它会更有效,更容易维护。

答案 2 :(得分:0)

您过早担心优化堆栈使用情况。

你指的是C ++。

对于Linux上的C ++,ubuntu 12.04和15.04的默认堆栈大小为8兆字节。

sizeof()高度和宽度各为4个字节。

如果你在Ubuntu 15.04上使用std :: string和gcc 4.9,那么     sizeof(an_empty_std_string_object)是8个字节(在堆栈上)

此外     sizeof(a_100_char_string_object)只有8个字节。     我猜想std :: string是一个围绕动态内存的简单包装器,但我从未检查过。

因此,一个8 MB的堆栈将容纳超过10 ^ 6的16字节对象。也许你可以使用递归来填充这个堆栈。

想象一下,您将对象的所有16个字节移动到堆中(即您将对象新建到堆中)

你仍然会在堆栈上使用8个字节(在64字节的linux上)来指向你的对象。

我没看过智能指针有多大,但它可能是16个字节,还不确定。

也许您担心将每个对象放入向量中。空向量是24个字节,因此是1000个元素向量,因此是1百万个元素向量,...

无论如何,如果你接近堆栈限制(这是可行的,我已经用递归算法完成了),在Linux中你可以改变堆栈大小...我已经尝试了1 GByte堆栈...只是看看递归程序会得到多远。没那么多了。 (对不起,我没有完成那个实验。)

  

声明我的Window类中的所有int和string类型   堆栈。

不,不是真的。您的int和字符串类型被声明为类实例的数据属性。如果您的类实例在堆上实例化(即使用new),那么该数据将在堆中,而不是在堆栈中。