【问题标题】:Do I need to free wchar memory allocated when using 'new' or does delete[] also free it?我需要释放使用'new'时分配的wchar内存还是delete []也释放它?
【发布时间】:2019-07-03 10:51:20
【问题描述】:

试图找出释放内存的正确方法,但我找不到明确的答案。我确定它就在那里,但我似乎找不到它,我有点困惑。

这就是我正在做的事情。我从 sUsers 创建一个新的 sStructUsers,然后为用户名分配内存

    struct sStructUsers 
        {
        TCHAR *sName;
        };

    sStructUsers *sUsers = new sStructUsers[TOTALUSERS]();

    // Allocate memory for the TCHARs in sStruct
    for (INT k = 0; k < TOTALUSERS; k++)
        {
        sUsers [k].sName =  (TCHAR*)calloc(128,sizeof(TCHAR))
        }

接下来,我对 sName 成员做任何我需要做的工作

    // do work here

现在,要清理,我要这样做吗:

    delete[] sUsers;

还是我这样做?

    for (INT k = 0; k < TOTALUSERS; k++)
        {
        free(sUsers[k].sName);
        }
    delete[] sUsers?

我不确定是否需要释放内存或者 delete[] 是否会处理它?

【问题讨论】:

  • 不要将 -alloc() 函数与 new 结合使用。
  • 除了 TCHAR sName[128] 之外,我还必须以某种方式为 sName 分配内存。那会吃掉堆栈。
  • new TCHAR[128] 有什么问题?
  • 两个分配都需要deallocated。仅在 sUsers 上调用 delete[ ] 也不会释放为名称分配的内存。为什么不改用std::stringstd::unique_ptr?为什么要通过手动内存管理使您的生活复杂化。
  • sStructUsers *sUsers = new sStructUsers[TOTALUSERS](); -- 你正在使用 C++。为什么不是:std::vector&lt;sStructUsers&gt; sUsers(TOTALUSERS);?然后TCHAR *sName; -- 你正在使用 C++。为什么不是:std::basic_string&lt;TCHAR&gt; sName;?或者 std::wstring sName;,如果这是一个 Unicode 应用程序并且您不再需要使用 TCHAR。与新手和非 C++ 程序员的普遍看法相反,到处使用指针和动态内存并不会使 C++ 应用看起来“专业”或“出色”。

标签: c++ arrays struct delete-operator


【解决方案1】:

如果你能提供帮助,请不要使用new。在大多数情况下,现代 C++ 中不需要 new。 您可以使用std::vectorstd::arraystd::string(可能是std::basic_string&lt;TCHAR&gt;)、std::unique_ptrstd::shared_ptr

如果你觉得你真的需要使用new,请创建一个特殊的类来处理这个问题。 IE。例如在构造函数中创建new,在析构函数中创建delete

当然,正如 cmets 中所说,永远不要将 new/delete 与 malloc/free 混为一谈。完全不需要在 C++ 中使用这些函数,因为这是 C 的残余。

编辑:添加示例,如何由类本身处理。

struct sStructUsers 
{
    const int MAX_NAME_SIZE = 128;
    sStructUsers()
    {
        sName = new TCHAR[MAX_NAME_SIZE];
    }
    ~sStructUsers()
    {
        delete sName;
    }
    TCHAR *sName;
};

那么你在使用这个类时不需要任何初始化/清理。

请注意,您通常甚至不需要这样做,您可以将您的类定义为:

struct sStructUsers 
{
    std::basic_string<TCHAR> sName;
};

并且免费拥有完整的string 功能。或者像这样,如果你真的需要一个指针:

struct sStructUsers 
{
    const int MAX_NAME_SIZE = 128;
    sStructUsers() : sName(new TCHAR[MAX_NAME_SIZE]) {}
    std::unique_ptr<TCHAR[]> sName;
};

或者,正如我之前提到的,使用其他标准容器。

【讨论】:

  • 你能给我看一个类中的构造函数/析构函数的例子来处理我正在尝试做的事情吗?
  • 添加到答案中。
  • 谢谢。 问题 1: 如果我使用 std::basic_string&lt;TCHAR&gt; sName;,我将如何在我的代码中引用 sUsers[1, 2, 3...x].sName问题 2: sName = new TCHAR[MAX_NAME_SIZE]; 不会从堆中取出内存吗?
  • 1.引用对象没有区别,它将是不同类型的对象,即std::basic_string vs char 指针。 1. 是的,在堆中分配的内存与basic_string 的情况一样,但在basic_string 的情况下,您不需要跟踪它并在不再需要内存时释放它(或有内存泄漏的风险)。
【解决方案2】:

建议更可取的容器、更惯用的 C++ 和更现代的实践的 cmets 和答案都很好。

但是您的第二个选项回答了您的直接问题

for (INT k = 0; k < TOTALUSERS; k++)
    {
    free(sUsers[k].sName);
    }
delete[] sUsers;

这不会泄漏内存。但是,您的第一个选项会泄漏,因为仅数组的 delete[] 不会释放其元素的堆内存。

简而言之,对每个new[] 使用delete[],对每个calloc 使用free

(只有这样才可能重构为更接近 C++,而不是 C 和 C++ 的混合)

【讨论】:

  • 好的,当我调用内存并结合 new 和 delete 时,我会做一个 free()。
【解决方案3】:

每个分配都应该被释放。通过一些代码。正如sklott 所写,有一些工具(容器和其他类)可以为您完成工作。如果其他一些代码不这样做,那么您的代码应该执行释放。

简而言之,您应该同时调用free(sUsers[k].sName)delete[] sUsers。就目前而言,删除[] sStructUserss 不会释放其中的指针。

(您也可以修改sStructUsers,使其析构函数直接或通过智能指针进行释放。)

(对于发布“永远不要将 new/delete 与 malloc/free 混淆”的回答者和评论者,请用 cmets 解释原因。了解建议和最佳实践背后的基本原理始终很重要。更新:显然你不能混合使用 new+free 或 malloc+delete 等;这些函数必须正确配对,以免出现堆损坏和泄漏。更好的问题是为什么不使用 new+delete 进行某些分配和malloc/calloc+free for others [更精细:CoTaskMemAlloc()、HeapAlloc()、VirtualAlloc() 或其他平台函数...]。)

【讨论】:

  • 在 malloc() 上引用 cppreference.com:This function does not call constructors or initialize memory in any way. There are no ready-to-use smart pointers that could guarantee that the matching deallocation function is called. The preferred method of memory allocation in C++ is using RAII-ready functions std::make_unique, std::make_shared, container constructors, etc, and, in low-level library code, new-expression.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-09
  • 2012-04-17
  • 1970-01-01
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多