`new / malloc`应该'删除/免费'的人?

时间:2012-07-26 02:34:09

标签: c++ ifstream delete-operator

在C / C ++中似乎是常识,在函数完成之前new/malloc某些内存应该delete/free的函数,对吗?

但是假设我有这样的问题,有一个函数reader会将文件中的块读取到缓冲区中,还有另一个函数consumer将使用这些缓冲区,

void reader(ifstream &ifs)
{
    char *buf = new char[100];
    ifs.read(buf, 100);
    save_buffer(buf);  //save this buf into a global array, say buf_array[10]
}

void consumer()
{
    for(int i = 0; i < 10; i++)
        consume( buf_array[i] );  //do something with those buffers read by reader
}

我的问题是,new内有许多内存资源reader,但reader不能delete,因为{{1}未使用这些缓冲区}}。 consumer应该consumer对这些缓冲区负责吗?

9 个答案:

答案 0 :(得分:4)

没有人说分配内存的功能应该释放内存。但通常相同的组件应该处理它。由于您的readerconsumer形成一对,因此他们可以将内存协调在一起。

答案 1 :(得分:1)

  

在C / C ++中似乎是常识,在函数完成之前new/malloc某些内存应该delete/free的函数,对吗?

不,这不一定是真的,你不必在同一个函数中释放内存,只要你在程序结束之前最终释放它。

C ++中可用的一种常见解决方案(但不包括C语言)是在析构函数中释放内存。如果在正确处理复制/移动构造函数和赋值运算符的同时传递包含动态分配的内存的对象,则在调用析构函数时将释放内存。

答案 2 :(得分:1)

原则是“对于每个new,应该有一个delete”。这并没有说明两个调用必须在同一个函数内(显然,这不会非常有用)。

您的阅读器分配和消费者释放的示例没有问题。

答案 3 :(得分:1)

您不必在同一个函数中执行new/malloc(分配)和delete/free(释放)。只要你的算法保证每个分配都被释放并且只释放一次,这样它就不会导致内存泄漏,那就没问题了。
实际上,分配和释放通常存在于不同的功能中。
记住这些:
1.使用相同的指针进行释放(当然可以传递指针)。如果对指针进行一些算术运算然后使用修改后的指针释放分配,即使指针仍指向分配区域,也会产生错误。
2.如上所述,您应该保证分配已经发布,并且只发布一次。额外的版本会导致错误。

答案 4 :(得分:1)

只要携带指向缓冲区的指针,就不需要在初始化它的同一个函数中释放已分配的缓冲区。

在您的情况下,consumer()应负责delete consumer分配的缓冲区。

至于你的第二个问题,消费者不知道缓冲区的结束位置;你需要以某种方式告诉它。您可以考虑定义一个封装缓冲区及其长度的新struct,而不是仅仅存储指向缓冲区的指针。这已经完成了:考虑使用std::string

答案 5 :(得分:1)

对其他人的答案略有不同:

是的,读者不能在读取功能中释放/删除内存,但我不会让消费者删除内存。在一个简单的情况下工作,但如果您有多个消费者(例如以不同的格式输出)怎么办?如果消费数据具有释放数据的副作用,那么在第一个消费者做到这一点后,你就无法对数据做任何其他事情。

我的阅读器中有一个cleanup()类型的方法,我明确要求在需要时清理缓冲区。这样,分配内存的模块负责释放它(即使它采用不同的方法)。

e.g。

Data d = Reader.read();
Consumer1.consume(d);
Consumer2.consume(d);
Reader.cleanup(d);
// d is no longer valid.

答案 6 :(得分:1)

您正在将buf的内容复制到实际为消费者提供的全局数组buf_arrray。因此,在上面的例子中,读者可以释放buf。

而且,新的/ mallocs应该释放内存的功能并不是必需的。指针可以传递。最后使用分配的内存的函数需要释放内存。

答案 7 :(得分:0)

您还可以阅读有关共享数组http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/shared_array.htm

的信息

使用共享数组,您可以在函数内部分配它们,并通过值将它们传递给其他函数。共享数组保留引用次数的内部计数,并在所有引用超出范围时自动删除内存。

例如

void bar( boost::shared_array< int > );

void foo()
{
    boost::shared_array< int > x ( new int[ 100 ] );
    bar( x );
    // because x has been passed to bar(), its reference count is incremented
    // and it will not only be deleted when everyone is finished with it!

    // do more things with x
} // the memory held by x is deleted

void bar( boost::shared_array< int > y )
{
    // Do things with y here
} // the memory held by y is not deleted here because foo() hasn't yet finished

答案 8 :(得分:0)

按照偏好的降序,您更喜欢:

  1. 使用auto存储类,因此会自动删除。
  2. 使用相同的代码分配和删除对象。
  3. 传递所有权,因此一个组件分配,另一个组件释放。
  4. 通过shared_ptr等方式共享所有权。
  5. 3和4几乎并列,但两者都落后于2,这远远落后于1.

    在这种情况下,你真正喜欢的是生产者和消费者以上的功能(或类等)的水平,以分配缓冲区,启动生产者和消费者,并在两者完成时删除缓冲区:

    class buffer { 
         std::vector<char> data;
    public:
         buffer() : data(100) {}
    };
    
    process_file(std::string const &name) { 
        std::vector<buffer> buffers(10);
    
        std::ifstream in(name);
    
        std::pair<std::ifstream *, std::vector<buffer> *> thread_data = {
            &in, &buffers
        };
    
        prod = start_thread(producer, (void *)&thread_data);
        cons = start_thread(consumer);
        join(prod);
        join(cons);
    }
    

    如果你能做到这一点,它可以帮助避免在管理内存时遇到麻烦很多