我是c ++的新手。
我有一个Rectangle
课程。当我创建这样的Rectangle
对象时:
Rectangle R1(10,10,90,20);
new
运算符创建它,那么它只会在堆上吗?(一般来说,在c ++中创建对象的正确方法是什么?)
据我了解,如果我在没有new
的情况下创建它,则该对象位于堆栈中,并且不需要在其生命周期结束时删除。如果用新的
Rectangle* R = new Rectangle(1,1,1,1);
它将被放置在堆上,需要使用delete
取消分配。
答案 0 :(得分:4)
Rectangle R1(10,10,90,20);
这会创建一个具有“自动”持续时间的变量。当代码流退出作用域时,它会自动销毁。如果它不在函数中,那意味着代码的执行完成。通常(但并非总是)它位于某种堆栈上。
Rectangle* R = new Rectangle(1,1,1,1);
Rectangle* P(new Rectangle(1,1,1,1)); //rarely used
这部分令人困惑:变量R
是一个具有自动持续时间的指针(如上所述)。它指向具有“动态”持续时间的Rectangle
。通常(但不总是)动态对象位于某种堆上。只有在使用delete R;
明确销毁矩形时,才会销毁该矩形。这意味着如果函数结束且没有R
的其他副本,则无法删除,并且在程序结束之前将保留在内存中。这称为内存泄漏。
在C ++中,动态内存最好用智能指针处理,例如std::unique_ptr
,这样即使代码崩溃,你也不会忘记删除它。
std::unique_ptr<Rectangle> R(new Rectangle(1,1,1,1));
答案 1 :(得分:1)
您说的很多内容都是实现细节或依赖于上下文。考虑一下:
// file.cpp
Rectangle r1(1,2,3,4);
int main()
{
Rectangle r2 = r1;
Rectangle * r3 = new Rectangle(r1);
}
此处r1
具有静态存储和静态(=永久)生存期,而r2
具有自动存储和自动(=范围)生命周期。也就是说,r1
在程序开始时构造并在结束时被销毁(在main
返回之后),而r2
在声明时被构造并在其范围的末尾被销毁(即函数体)在这种情况下的范围)。
指针r3
指向动态存储和动态(=手动)生存期的Rectangle
对象。对象*r3
在new
表达式中生效,并且只有在用户请求时才会通过匹配的delete
表达式(或者可能是手动析构函数调用)来销毁它。由于我们不销毁它,实际上这是 leak 。
对*r3
使用的内存一无所知,除了该内存由静态成员函数Rectangle::operator new()
分配(如果存在),或者全局分配分配函数::operator new
。全局版本的内存通常被称为“免费商店”。
(所有三个对象r1
,r2
和*r3
应该相等,因为r2
和*r3
被构造为r1
的副本。)
当您考虑成员变量时,情况变得更加有趣:struct Foo { Rectangle r; };
。
答案 2 :(得分:0)
R1
。这意味着,在实践中,它将被分配在类似堆栈的结构上。它不必介意你,'堆栈'只是方便和常见。你必须调用new
(或malloc
,如果你真的想要一些愚蠢的理由......不要)动态分配内存。
见上文。
是的,new
您必须delete
的任何内容。通常,课程会为您管理。以std::vector<T>
为例。您在堆栈上分配vector
,但内部数据(即T的数组)是动态分配的。当vector
超出范围时,delete []
为其中的动态分配数组提供了析构函数,使您可以对基础内存管理细节保持愉快的了解。