来自C#背景,我对C ++的内存管理只有最模糊的想法 - 我所知道的是我必须手动释放内存。因此,我的C ++代码编写方式使std::vector
,std::list
,std::map
类型的对象可以自由实例化,使用,但不会被释放。
直到我几乎完成了我的程序,我才意识到这一点,现在我的代码由以下几种模式组成:
struct Point_2
{
double x;
double y;
};
struct Point_3
{
double x;
double y;
double z;
};
list<list<Point_2>> Computation::ComputationJob
(list<Point_3>pts3D, vector<Point_2>vectors)
{
map<Point_2, double> pt2DMap=ConstructPointMap(pts3D);
vector<Point_2> vectorList = ConstructVectors(vectors);
list<list<Point_2>> faceList2D=ConstructPoints(vectorList , pt2DMap);
return faceList2D;
}
我的问题是,我必须释放列表用法的 every.single.one (在上面的示例中,这意味着我必须释放{{1 },pt2DMap
和vectorList
)?那将是非常乏味的!我也可以重写我的faceList2D
类,以便它不易发生内存泄漏。
知道如何解决这个问题吗?
答案 0 :(得分:11)
否:如果对象未分配new
,则无需明确释放/删除它们。当它们超出范围时,它们会自动解除分配。当发生这种情况时,会调用析构函数,它应该释放它们引用的所有对象。 (这称为Resource Acquisition Is Initialization, or RAII,std::list
和std::vector
等标准类遵循此模式。)
如果您使用new
,则应使用智能指针(scoped_ptr
)或明确调用delete
。调用delete
的最佳位置是析构函数(出于异常安全的原因),尽管应尽可能使用智能指针。
答案 1 :(得分:2)
我能说的一般是C ++标准容器在场景下复制你的对象。你无法控制它。这意味着如果构造对象(在您的情况下为Point_2
)涉及任何资源分配(例如:new
或malloc
调用),那么您必须编写自定义版本的复制构造函数和析构函数,使得当地图决定复制Point_2
时,这会使其表现得非常明显。通常这涉及引用计数等技术。
许多人发现将复杂对象的指针放入标准容器而不是对象本身更容易。
如果你没有为你的对象做任何特殊的构造函数或析构函数(现在看来就是这种情况),那就没有任何问题了。一些容器(如地图)将在场景下进行动态分配,但这对您来说实际上是不可见的。 容器担心资源分配。你只需要担心你的。
答案 2 :(得分:0)
所有stl容器都会自动清理其内容,您必须关注的是清理动态分配的数据(即规则是:处理指针)。
例如,如果您有list<MyType>
- 列表中包含某些自定义类型的对象 - 在销毁时它将调用~MyType()
,它应该正确清理对象内容(即如果MyType有一些指向内部分配内存的指针,你应该在析构函数中删除它们。)
另一方面,如果你开始使用list<MyType*>
- 容器现在如何正确地清理它,它包含一些标量值(就像整数一样)并且只删除指针本身,而不清除尖头内容,所以你需要手动清理它。
一个非常好的建议(很多年前曾帮助过我:))当从Java / C#切换到C ++时,要仔细跟踪每个动态内存对象的生命周期:a)创建它的地方,b)它被使用的地方,c )它何时何地被删除。 确保它只被清理一次,之后不会被引用!