让我们说我有一个代表我申请的课程:(很抱歉没有同时显示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
类中的所有string
和Window
类型都在堆栈中声明。在某些时候,如果我继续在这些类中的堆栈中声明内容,我将最终导致堆栈溢出......对吗?
所以我的问题是 ...为什么你要在堆栈上声明东西?我不应该这样做吗?
// ...
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;
...
不同之处在于整数和字符串的内存现在在堆上声明。
答案 0 :(得分:5)
Why would you ever want to declare stuff on the stack?
我能想到的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),那么该数据将在堆中,而不是在堆栈中。