如何正确使用 “delete” 关键字以避免在 C++ 中出现内存泄漏。

huangapple go评论68阅读模式
英文:

how to use delete keyword correctly to avoid memory leaks in c++

问题

我在geek for geeks网站上看到这段代码,并根据valgrind的指导发现第58行存在内存泄漏问题,但我看不到如何修复它以使代码更好,因为如果我们删除那个new,则分配给v[i]的值也会被删除,没有值传递给它!!

我是一个编程新手!!

以下是代码:

// 创建指针向量的C++程序
#include <bits/stdc++.h>

using namespace std;

void insert_element(vector<int*>& v, int i)
{
	// 声明和输入元素的值
	int a;
	cin >> a;

	// 将地址分配给第i个元素
	v[i] = new int(a);
}

void print_vector(vector<int*>& v)
{
	// 打印向量的元素
	for (int i = 0; i < v.size(); i++) {
		cout << *(v[i]) << " ";
	}

	cout << endl;
}

void delete_element(vector<int*>& v, int pos)
{
	// 超出限制的位置
	if (pos <= 0 || pos > v.size())
		return;

	// 将位置转换为索引号
	pos = pos - 1;

	// 释放指针的空间
	delete v[pos];

	// 从向量中删除元素
	v.erase(v.begin() + pos);
}

int main()
{
	cout << "输入向量的大小:";

	// 向量的大小
	int n;
	cin >> n;

	// 创建一个向量
	vector<int*> v(n, nullptr);

	cout << "输入向量的元素:";
	for (int i = 0; i < n; i++) {

		// 在向量v中插入n个元素
		insert_element(v, i);
	}

	cout << "之前:";
	// 打印向量
	print_vector(v);

	cout << "输入要删除的位置:";

	int pos;
	cin >> pos;

	// 从位置pos删除元素
	delete_element(v, pos);

	cout << "之后:";
	// 打印向量
	print_vector(v);

	return 0;
}

我尝试删除它,但它会报错,说在那个地方期望使用delete关键字来删除指针。

错误信息:类型'class std::vector<int*>'的参数传递给'delete',但是需要一个指针。

英文:

I see this code in geek for geeks and it has memory leak on 58 line as guided by valgrind ,
i don't see any way how to fix this to make it a better code, cause if we delete that new then assigned v[i] also delete and no value get inside it !!
i am a beginner to coding!!
here is the code

// C++ Program to create
// vector of pointer
#include&lt;bits/stdc++.h&gt;
using namespace std;
void insert_element(vector&lt;int*&gt;&amp; v, int i)
{
// declaration and input of values of elements
int a;
cin &gt;&gt; a;
// allocating address to i element
v[i] = new int(a);
}
void print_vector(vector&lt;int*&gt;&amp; v)
{
// printing elements of the vector
for (int i = 0; i &lt; v.size(); i++) {
cout &lt;&lt; *(v[i]) &lt;&lt; &quot; &quot;;
}
cout &lt;&lt; endl;
}
void delete_element(vector&lt;int*&gt;&amp; v, int pos)
{
// Out of limit positions
if (pos &lt;= 0 || pos &gt; v.size())
return;
// converting position into index number
pos = pos - 1;
// free the space from pointer
delete v[pos];
// removing element from the vector
v.erase(v.begin() + pos);
}
int main()
{
cout &lt;&lt; &quot;Enter size of vector: &quot;;
// size of vector
int n;
cin &gt;&gt; n;
// create a vector
vector&lt;int*&gt; v(n, nullptr);
cout &lt;&lt; &quot;Enter elements of vector: &quot;;
for (int i = 0; i &lt; n; i++) {
// inserting n elements inside v vector
insert_element(v, i);
}
cout &lt;&lt; &quot;Before: &quot;;
// printing vector
print_vector(v);
cout &lt;&lt; &quot;Enter position to remove: &quot;;
int pos;
cin &gt;&gt; pos;
// delete element from pos position
delete_element(v, pos);
cout &lt;&lt; &quot;After: &quot;;
// printing vector
print_vector(v);
return 0;
}

i tried delete it but it says expected pointer in that place with delete keyword

error: type ‘class std::vector<int*>’ argument given to ‘delete’, expected pointer
15 | delete v;

答案1

得分: 1

最简单避免内存泄漏的方法是...不要在对象构造和销毁之外的任何地方使用new/delete表达式。这是RAII原则的一部分。

Valgrind报告的是,第58行调用的函数(insert_element)创建了"泄漏"的自由存储器内存,但该泄漏发生在main()函数退出时。指针向量被销毁,但自由存储器中的对象没有被销毁。在大多数情况下,这是一个无害的情况,但让我们正式一点。

我们的选择是:

A.) 完全避免额外分配。在这里不是必需的。我们可以使用vector<int>在这种特殊情况下,这是一个更可取的解决方案。通常情况下,指针的大小等于或大于一个int。向量已经在自由存储器中工作。

B.) 使用一个会自动删除元素的向量。这是容器的责任。但这将需要对代码进行多次更改,因为类型本身已经改变了。我们可以通过声明类型别名来避免这一点。

    // 在代码中的任何地方使用它。
using  MyVector = std::vector<std::unique_ptr<int>>;

这不是一个很好的解决方案。我们过度设计了容器,而且我们实际上不能创建它的副本。对于原始代码来说也是如此 - 向量实际上不能被复制,第二个副本将具有指向相同内存的指针,但清除一个副本将导致另一个副本中的指针"悬挂",指向不再存在的对象的无效内存。也许你需要一个具有引用计数的智能指针 - shared_ptr,甚至可能需要一个自定义的删除器和分配器。为了存储一个单独的int,这太过于复杂了。

C.) 一个"机械师"的解决方案:通过在有问题的地方应用胶带代码来修复问题

    // 打印向量
print_vector(v);
for(auto &item : v)
delete item;
return 0;

附注:请确保这不是"鸭带代码",即在每个地方修补每个漏洞的脆弱解决方案。除了Ducktape品牌的版权问题之外,糟糕编写的代码,在糟糕维护的情况下,很快变成一个难以阅读的混乱,跟随的修复可能完全错误,项目崩溃。特别是如果负责修复的人没有编写原始代码。

英文:

The simplest way to avoid leaks is... not to use new\delete expressions anywhere outside of object construction and destruction. That's the part of RAII principle.

What valgrind reports, is that the function called on 58th line (insert_element) had created "leaked" free store memory, but that leak happens on exit from the main()function. The vector of pointers is destroyed, but the objects in free store aren't. In most cases it's a harmless scenario, but let be formal.

Our choices are

A.) Avoid extra allocation at all. It's not necessary here. we can use vector&lt;int&gt;. In this particular case it's a preferable solution. Usually the pointer's size is equal or greater in size than an int. Vector already works with free store.

B.) Use a vector that will delete elements automatically. Seriously, that's the responsibility of a container. But that would require multiple changes in code, because the type itself has changed. We can avoid that y declaring a type-alias.

    // Use it everywhere in code.
using  MyVector = std::vector&lt;std::unique_ptr&lt;int&gt;&gt;

That's not a great solution. We overengineered the container also we can't actually make a copy of it. The latter is true for original code - the vector isn't really copyable, a second copy would have pointers referring to same memory, but clearing one copy would cause pointers in the other copy to "dangle" - to point at invalid memory where object no longer exists.
You might need a smart pointer with reference counting instead -shared_ptr, even maybe a custom deleter and allocator. It's too much to store a single int.

C.) A "mechanist" solution: fix the problem by applying ducttape code where it is broken:

    // printing vector
print_vector(v);
for( auto &amp;item : v)
delete item;
return 0;
}

PS. Be sure it's not a "ducktape code", i.e. a fragile solution where you patch every hole and apply it everywhere. Aside from the copyright issues with Ducktape brand, a badly written code, while badly maintained, quickly becomes an unreadable mess where following fixes may be utterly wrong and the project falls apart. Especially if one who does fixing didn't wrote the original.

huangapple
  • 本文由 发表于 2023年2月16日 15:23:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/75468990.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定