谁负责释放分配的内存?

时间:2012-03-13 23:02:01

标签: c++ free delete-operator

请考虑以下代码段

void xyz(CString **mapping)
{
    *mappings = new CString[10];
    (*mappings)[0] = "hello";
    //...
}

void main(int argc, char **argv)
{
    CString *tmp;
    xyz(&tmp);
    // now we have the CString array defined in xyz
}

我要做的是用main填充一个var,由另一个函数生成一些值。我读到了删除/释放与分配的功能相同的最佳实践。在这种情况下这是不可能的,因为xyz存在的唯一原因是生成数据(这只是一个例子,在实际情况下,xyz ;中会有更多的复杂性))。我还考虑在main中的堆栈上创建一个数组并将其传递给函数,但在我的情况下,当时没有修复数组的大小(在xyz中确定)。清理已分配内存的最简洁,最常用的方法是什么? 如果我们有一个方法xyz的对象,那么最佳实践是什么?创建另一个方法(例如freeMapping()),在处理数据后必须由调用者调用?

3 个答案:

答案 0 :(得分:1)

人们多年来使用过许多不同的方案,有些方案更好或更差。良好的策略定义了一种严格且一致的模式,该模式为资源的“所有权”建立规则,即清理和确保不会非法访问资源的责任。成功策略的规则也是这样的,只有资源的本地视图及其使用方式才是安全访问资源的必要条件。

您应该在现代C ++中使用的策略称为RAII或“资源获取是初始化”。该名称的含义是获取的任何资源都应该是初始化。例如:

std::string s = "Hello, World";

此代码获取一些内存作为存储字符串数据的资源,但您看到的只是字符串已初始化。初始化的对象拥有内存。这意味着它负责管理内存的生命周期并限制对内存的访问。使用该对象的代码根本不需要考虑资源。它只需要确保它正确使用对象本身,并且将依次正确管理隐藏资源的生命周期。

使用RAII不仅方便了本地管理资源的正常管理,还极大地简化了在异常情况下正确清理资源的过程。当由于异常而退出作用域时,C ++保证销毁该作用域中所有完全构造的对象。如果通过对象析构函数完成清理资源所需的任务,那么资源不会泄漏,并且不需要为使用资源的每个作用域添加显式异常处理。

C ++已经包含了许多类型资源的资源拥有类。对于动态大小的数组,请使用std::vector

std::vector<CString> xyz()
{
    // C++11
    return {"hello",...};

    // or C++03
    std::vector<CString> mappings;
    mappings.push_back("hello");
    ...
    return mappings
}

void main(int argc, char **argv)
{
    std::vector<CString> tmp = xyz();
    // now we have the CString array defined in xyz
    // the array gets automatically cleaned up by std::vector's destructor
}

答案 1 :(得分:0)

你在这里展示是不好的做法。所以它有两个解决方案:

  1. 在主要功能中分配并释放内存。

  2. 创建一个类,它将负责该字符串的所有操作并在main函数中使用它。

答案 2 :(得分:0)

RAII样式类(在其dtor中释放对象的包装器)是处理此类事物的常用方法(请参阅std :: auto_ptr或一些更现代的替代方法,例如boost :: scoped_ptr或std: :的unique_ptr)。当auto_ptr / unique_ptr超出范围时,将自动调用delete。

传入对调用者堆栈上创建的std :: vector的引用可能有效。

按值返回std :: vector很容易理解,并且可能会根据您的要求执行得很好。