繁体   English   中英

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

[英]Why would you use the stack if there is a possibility of stack overflow

假设我有一个代表我的应用程序的类:(很抱歉,没有同时显示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()
{

}

Window类中的所有intstring类型都在堆栈上声明。 在某些时候,如果我继续在这些类中的堆栈上声明一些东西,我将最终导致堆栈溢出……对吗?

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

// ...
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;

...

区别在于,现在在堆上声明了整数和字符串的内存。

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

我能想到的2个原因:

  1. 性能:堆栈非常快。 我记得在某处听到过这种声音,但是提高性能的最好方法是避免绊倒。

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

即使将window声明为unique_ptr<Window> window窗口, unique_ptr<Window> window在堆栈上声明某些内容。 在这种情况下, unique_ptr<Window>的实例。 在堆栈上声明int和其他小的原语或结构是很好的,因为即使在堆上声明它们,也需要在堆栈上声明指向它们的指针。 您将始终需要在堆中保留指向堆中位置的指针,因此,如果您的数据类型小于指针(或接近相同大小),则将其保存在堆栈上的效率甚至比将其保持在堆栈上的效率更高。堆。 这是因为访问堆栈要比堆快,并且在内存方面,当存储在堆上时,必须存储两个对象(指针和对象本身),而存储在栈上则只能存储一个对象。

std::string为例。 它可能在内部持有一个指向堆上原始数据存储位置的指针。 因此,在堆栈上,您要持有一个指针,在堆栈上,则要保留原始数据(字符串字面量有所不同,一般思路仍然存在)。

通常,除非将int作为数组的地址,否则将int存储在unique_ptr几乎没有意义。 如果仅将其声明为原始int,则效率更高且易于维护。

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

您指出了C ++。

对于Linux上的C ++,Ubuntu 12.04和15.04的默认堆栈大小为8 MB。

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的堆栈将容纳16个字节对象中的10 ^ 6个以上。 也许您可以使用递归来填充此堆栈。


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

您仍将在堆栈上使用8字节(在64字节linux上)指向您的对象。

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


也许您担心到足以将每个对象放入向量中。 空向量为24个字节,一个1000元素向量也是如此,一百万个元素向量也是如此,...

无论如何,如果您接近堆栈限制(这是可行的,我已经使用递归算法完成了此操作),那么在Linux中,您可以更改堆栈大小...我尝试了1 GB的堆栈...只是为了看看有多大递归程序将得到。 没那么远。 (抱歉,我没有完成该实验。)


Window类中的所有int和string类型都在堆栈上声明。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM