简体   繁体   English

谁负责释放分配的内存?

[英]Who is responsible for freeing allocated memory?

Consider the following code snippet 考虑以下代码片段

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
}

What I'm trying to do is to fill a var from main with some values which are generated by another function. 我想要做的是用另一个函数生成的一些值来填充main中的var。 I read that its best practise to delete/free in the same function as it was allocated. 我读到最好的做法是删除/释放与分配它相同的功能。 This is not possible in this case because the only reason why xyz exists is to generate data (this is just an example, in real cases there would be some more complexity in xyz ; )). 在这种情况下,这是不可能的,因为xyz存在的唯一原因是生成数据(这只是一个示例,在实际情况下, xyz ;会有更多的复杂性)。 I also considered to create an array on the stack in main and pass it to the function but in my case the size of the array is not fix at that time (it is determined in xyz ). 我还考虑过在main的堆栈上创建一个数组,然后将其传递给函数,但就我而言,当时数组的大小尚不固定(由xyz确定)。 What is the cleanest and most common way to clean up allocated memory? 清理分配的内存的最干净,最常见的方法是什么? If we had an object with method xyz what would be best practice then? 如果我们有一个对象使用xyz方法,那么最佳做法是什么? To create another method (for example freeMapping() ) which has to be invoked by the caller after he processed the data? 要创建另一个方法(例如freeMapping() ),该方法必须在调用者处理完数据后由调用者调用?

There are many different schemes that people have used over the years, some better or worse. 这些年来,人们使用了许多不同的方案,有些方案的优缺点是不同的。 Good strategies define a rigid and consistent pattern that establishes rules for 'ownership' of a resource, ie responsibility for cleaning up and ensuring nothing accesses the resource illegally. 好的策略定义了一种僵化且一致的模式,该模式为资源的“所有权”建立了规则,即负责清理并确保没有非法访问资源的责任。 The rules of successful strategies are also such that only a local view of the resource and how it's used is necessary for safe access to the resource. 成功策略的规则还要求,只有对资源及其使用方式的本地视图才能安全访问资源。

The strategy you should be using in modern C++ is called RAII or 'resource acquisition is initialization'. 在现代C ++中应使用的策略称为RAII或“资源获取即初始化”。 What that name means is that any resource that's acquired should be an initialization. 该名称的含义是,获取的任何资源都应该是初始化。 For example: 例如:

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

This code acquires some memory as a resource for storing the string data, but all you see is that the string is initialized. 该代码获取一些内存作为存储字符串数据的资源,但是您所看到的只是字符串已初始化。 The object that is initialized owns the memory. 初始化的对象拥有内存。 That means it's responsible for managing the memory's lifetime and restricting access to it. 这意味着它负责管理内存的寿命并限制对其的访问。 Code using the object doesn't need to consider the resource at all. 使用该对象的代码根本不需要考虑资源。 It only has to be sure it's using the object itself correctly, and the hidden resource's lifetime will be managed correctly in turn. 只需确保它正确使用了对象本身,就可以依次正确管理隐藏资源的生存期。

Using RAII is not only convenient for keeping normal management of a resource localized, it also greatly simplifies correctly cleaning up resources in the presence of exceptions. 使用RAII不仅可以方便地对资源进行正常的本地化管理,而且还可以大大简化异常情况下正确清理资源的过程。 When a scope is exited due to an exception, C++ guarantees to destroy all completely constructed objects in that scope. 当由于异常退出作用域时,C ++保证销毁该作用域中所有完全构造的对象。 If the necessary tasks for cleaning up resources is done by object destructors, then the resources will not leak, and there's no need to add explicit exception handling to every scope in which a resource is used. 如果清理资源的必要任务是由对象析构函数完成的,那么资源将不会泄漏,也无需向使用资源的每个范围添加显式异常处理。

C++ already includes resource owning classes for many types of resources. C ++已经包括许多资源类型的资源拥有类。 For a dynamically sized array use a std::vector : 对于动态大小的数组,请使用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
}

It is bad practice that you show here. 您在此处显示这是一种不好的做法。 So it has 2 solutions: 因此,它有2个解决方案:

  1. Allocate and free memory in main function. 在主要功能中分配和释放内存。

  2. Make a class, which will be responsible for all operations with that string and use it in main function. 创建一个类,它将负责该字符串的所有操作并将其用于main函数。

An RAII style class (a wrapper that frees the object in its dtor) is a common way to handle this sort of thing (see std::auto_ptr or some of the more modern alternatives such as boost::scoped_ptr or std::unique_ptr). RAII样式类(用于在其dtor中释放对象的包装器)是处理此类问题的常用方法(请参见std :: auto_ptr或一些更现代的替代方法,例如boost :: scoped_ptr或std :: unique_ptr) 。 When the auto_ptr/unique_ptr goes out of scope delete is called automatically. 当auto_ptr / unique_ptr超出范围时,将自动调用删除。

Passing in a reference to a std::vector created on the callers stack may work. 传递对在调用程序堆栈上创建的std :: vector的引用可能会起作用。

Returning a std::vector by value is easy to understand and may perform quite well depending on your requirements. 通过值返回std :: vector很容易理解,并且根据您的要求可能执行得很好。

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

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