“new/malloc”应该“delete/free”的人
The one who `new/malloc` should `delete/free`?
在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
}
我的问题是,许多内存资源都在reader
中new
,但reader
不能delete
,因为这些缓冲区还没有被consumer
使用。consumer
是否应该负责delete
处理这些缓冲区?
没有人说分配内存的函数应该释放内存。但通常应该由同一个组件来处理。因为reader
和consumer
是一对,所以它们可以一起协调内存。
在C/C++中,
new/malloc
一些内存的函数应该在函数完成之前delete/free
它们,这似乎是一个常识,对吧?
不,这不一定是真的,你不必在同一个函数中释放内存,只要你最终在程序结束前释放它。
C++中(但C中没有)的一个常见解决方案是解除析构函数中内存的分配。如果在正确处理复制/移动构造函数和赋值运算符的同时传递包含动态分配内存的对象,则在调用析构函数时将释放内存。
原则是"对于每个new
,都应该有一个delete
"。这并没有说明两个调用必须在同一个函数内(显然,这不是很有用)。
读者分配和消费者释放的例子没有问题。
您不需要在初始化缓冲区的同一函数中释放已分配的缓冲区,只要您携带一个指向缓冲区的指针即可。
在您的情况下,consumer()
应该负责delete
分配给consumer
的缓冲区。
至于你的第二个问题,消费者不知道缓冲区在哪里结束;你需要以某种方式告诉它。您可以考虑定义一个新的struct
来封装缓冲区及其长度,而不是只存储指向缓冲区的指针。这已经完成了:考虑使用std::string
。
您正在将buf的内容复制到一个全局数组buf_array,该数组实际上为消费者提供信息。因此,在上面的例子中,读者可以释放buf。
而且,也没有要求新的mallocs应该释放内存的函数。指针可以四处传递。最后使用分配内存的函数需要释放内存。
您不必在同一函数中执行new/malloc
(分配)和delete/free
(发布)。只要你的算法保证每个分配都会被释放,并且只被释放一次,这样就不会导致内存泄漏,这是可以的
事实上,分配和发布通常存在于单独的功能中
请记住:
1.使用相同的指针进行释放(当然,您可以将指针四处传递)。如果对指针进行一些运算,然后使用修改后的指针释放分配,即使指针仍然指向分配区域,也会产生错误
2.如上所述,您应该保证分配被释放,并且只释放一次。附加释放会导致错误。
与其他人的答案略有不同:
是的,阅读器在读取功能中不释放/删除内存是可以的,但我不会让消费者删除内存。在一个简单的情况下是可行的,但如果你有多个消费者(例如以不同的格式输出)怎么办?如果消费数据有释放数据的副作用,那么在第一个消费者做了它的事情之后,你就不能对数据做任何其他事情。
我的阅读器中会有一个cleanup()
类型的方法,我会在需要时显式调用它来清理缓冲区。通过这种方式,分配内存的模块负责释放内存(即使它使用不同的方法)。
例如
Data d = Reader.read();
Consumer1.consume(d);
Consumer2.consume(d);
Reader.cleanup(d);
// d is no longer valid.
您还可以阅读有关共享数组的内容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
按偏好降序排列:
- 使用
auto
存储类,因此会自动删除 - 使用相同的代码分配和删除对象
- 传递所有权,这样一个组件分配,另一个组件释放
- 通过类似
shared_ptr
的方式共享所有权
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);
}
如果你能做到这一点,它可以帮助避免在管理内存时出现很多头痛的问题。
- 寻找C++吃得最少的人
- 初始化cv :: mat ::具有int类型的定义大小的人
- 与在C 中覆盖的人混淆了
- 任何熟悉Codecademy C++/程序的人都可以帮助解决菜鸟问题吗?
- 我如何向只用Fortran 77编码的人解释面向对象编程?
- “new/malloc”应该“delete/free”的人
- 基于malloc/free的STL分配器
- 使用asctime_s,可以与解释参数类型c ++的人一起做
- 这样一个垂头丧气的人安全吗
- 对列表中最有可能由列表顶部的人说出的积极单词和列表末尾很少说出的单词进行排序
- c++程序来比较年龄,如果5个人,并打印最年长的人的名字
- 把最胖的人扔出超载的飞机
- 如何检查new[]使用free()的结果
- 在动态内存池中,对malloc的调用必须与对free的调用匹配
- 存储和回收没有malloc和free的堆分配的可变大小对象
- c++编辑器的选择,为Java的人
- "lock-free"的含义是否由C++标准定义?
- 如何将此程序中的员工数据从最年长的人排序为最年轻的人?C++
- 使用opencv C++在检测到的人脸上放置图像
- 查找在给定指针类型上调用 free 的位置