包含矢量指针的结构的内存释放问题



我在Linux环境中工作,c++。这个简单的代码无法释放指针的内存,我不确定为什么。

如果我实现代码为矢量指针 Var 分配内存,然后使用 swap(( 方法正确清除矢量数据以删除矢量条目,它也不会释放结构指针。 所以我将代码简化为你在下面看到的,当我调用 delete 时它仍然没有释放内存。

使用矢量可能会导致问题,因为没有已知的大小,不确定如何解决这个问题。无论是那个还是标准库都不需要将内存释放回操作系统。

#include <vector>
typedef struct
{
char                Name[MAX_VAR_NAME_LEN + 1];    
UINT8              *pValue;
}DATA_STRUCT;
typedef struct
{
char            SomeArray[SOME_MAX_ARRAY_SIZE;
UINT16          VarCount;
std::vector<DATA_STRUCT>  *Var;
}SOME_STRUCT;
int main(int argc, char* argv[])
{
SOME_STRUCT lpStruct* = new SOME_STRUCT;//lpStruct is allocated
///blah blah blah
delete lpStruct;//lpStruct is not released
return 1;
}

您的主要问题似乎是为什么删除指针不会将指向的地址设置为 null。我会回答这个问题,但也试着在回答的最后睁开你的眼睛,看看一些更现代的C++风格。


通常,您可以delete来自任何表达式(例如函数调用(的指针。在这种情况下,不可能将返回的指针设置为 null:
Thing* getThingToDelete();
void main(){
delete getThingToDelete();
// how can delete set the returned pointer to null???
}

因此,如果您拥有一个有时允许为 null 的指针,那么在delete该指针后将该指针设置为nullptr是一种记账形式,这是一种很好的做法(但不是必需的(。这只是在处理指针和手动内存分配时要习惯的事情,以及严格考虑所有权,正确使用newdeletenew[]delete[],检查nullptr,并跟踪数组大小。真的,要考虑的事情很多,而且很快就会妨碍您最初打算做的事情。正是出于这个原因,存在许多现代C++功能来隐藏所有这些噪音并处理所有细节,而无需程序员的有意识干预。下面是一个示例。


考虑一下代码的现代改造:
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
struct DATA_STRUCT {
std::string Name;
int Value;
};
struct SOME_STRUCT {
// I'm not sure if SomeArray is supposed to be used as a string or array
// so here's both:
std::string SomeString;
std::vector<char> SomeCharArray;
// the need for VarCount is unclear, but if you want to get the number
// of elements in Var, you simply write:
// > Var.size()
std::vector<DATA_STRUCT> Var;
};
int main(int argc, char** argv){
SOME_STRUCT s;
// some example usage:
// is there anything in s?
bool hasAnyVars = !s.Var.empty();
// add a new value to s, with value=16 and name="Jeffrey"
s.Var.push_back({ "Jeffrey", 16 });
// how many items are in s now?
size_t numItems = s.Var.size();
// is there anyone named Helga?
bool foundHelga = std::find_if(s.Var.begin(), s.Var.end(), [](const auto& x){
return x.Name == "Helga";
}) != s.Var.end();
// print every thing in the list
for (const auto& x : s.Var){
std::cout << "Name=" << x.Name << ", value=" << x.Value << 'n';
}
// end of examples
return 1;
}

请注意,我根本没有使用任何指针。此外,此代码没有内存泄漏,我从来不需要考虑手动分配。如您所见,现代C++允许您的程序具有比以前更丰富、更清晰的语义,并且只需几行代码即可完成大量常见任务。在我的示例中出现了许多可能不熟悉的内容,我将在此处提供链接:

  • string- C 风格字符串的超级简单、防白痴替代品
  • vector- 显然你已经看到了这个,但文档显示了许多你可能不知道的有用的成员函数
  • 迭代器 - 标准库容器中的通用指针访问器,与标准算法配合得很好
  • <algorithms>库中的find_if和朋友 - 适用于任何容器的方便、通用的搜索功能
  • lambda 表达式 - 匿名的局部函数,也可以引用局部变量
  • auto关键字 - 自动推断变量的类型;可以为您节省大量的打字和维护工作
  • rangedfor-loops - 在容器中的所有元素上编写for循环的最短、最简单的方法

还要注意,如果您确实需要指针语义,例如对一个对象的多个引用或想要简单地管理多态对象的生存期,还有:

  • unique_ptr- 一个智能指针,当您使用完它时会自动删除自己。只有一个所有者。
  • shared_ptr- 可以有多个引用的智能指针。在代码中的所有位置都使用它时删除自身。

我确实让你们的名字基本保持不变,尽管现在很少看到用所有大写字母编写的代码。有时让我担心FORTRAN回来对我大喊大叫,但这对我来说是主观的,这实际上是一个人自己的喜好问题。

最新更新