【问题标题】:When to delete allocated memory of returned value何时删除返回值的分配内存
【发布时间】:2016-01-22 11:29:34
【问题描述】:

当我删除给定函数“lowerCaseWord(char* a)”的b内存时?我需要返回b的值,所以不能在“return b;”行之前删除它。我需要使用另一个变量吗?还是编译器会单独删除它(即使它的编程不好)?

char* lowerCaseWord(char* a)
{
    char *b=new char[strlen(a)];
    for (int i = 0; i < strlen(a); i++)
    {
        b[i] = tolower(a[i]);   
    }
    return b;

}

【问题讨论】:

  • @Moo-Juice C++。尝试使用 C++ 编译器进行编译。
  • @zenith,哦,是的 - 它将使用 C++ 编译器进行编译 - C 也是如此。我的意思是,如果你编写的是 C++ 而不是 C :)

标签: c++ pointers memory-management


【解决方案1】:

您需要自己在函数之外 delete[] 它,即使这不是一个好习惯。如:

char* rtv = lowerCaseWord(a);
// process with rtv
// ...
delete[] rtv;

最好使用smart pointer,避免手动管理内存,如:

std::unique_ptr<char[]> lowerCaseWord(char* a)
{
    ...
}

然后

std::unique_ptr<char[]> rtv = lowerCaseWord(a);
// process with rtv
// ...

正如@FrerichRaabe 所指出的,基本上使用原始指针不是一个好主意,您可能想直接使用std::string

【讨论】:

  • 当然,如果你愿意使用std::shared_ptr,你也可以首先对普通的std::string对象进行操作。
  • std::shared_ptr&lt;char&gt; 是单个char,不是吗?
  • 对,很抱歉造成混乱。我认为您需要使用特殊的删除器,但类型与原始代码中的类型相同。但是,这并没有让用户清楚地知道这个东西管理着一个动态分配的数组。使用 unique_ptr 可能会更好,但我认为真正的解决方案是使用 std::string
  • const char *a 确定吗?
【解决方案2】:

对于初学者来说,功能是错误的

char* lowerCaseWord(char* a)
                    ^^^^
{
    char *b=new char[strlen(a)];
                     ^^^^^^^^^
    for (int i = 0; i < strlen(a); i++)
         ^^^
    {
        b[i] = tolower(a[i]);   
                       ^^^^
    }
    return b;
}

它得到一个字符串但不返回一个字符串,因为新的字符数组不包括终止零。

它不能处理常量对象,例如字符串文字。更让用户感到困惑,因为他们会认为他们的原始字符串在函数中被改变了。

标准函数tolower 也考虑转换为unsigned char 的字符。

那是根据 C 标准(7.4 字符处理)

  1. ...在所有情况下,参数都是一个 int,其值应为 可表示为 unsigned char 或应等于 宏EOF。如果参数有任何其他值,行为是 未定义

并且变量i的类型应该是size_t,因为它是具有函数strlen的返回值的类型。

你必须写

char* lowerCaseWord( const char *a )
{
    char *b = new char[std::strlen( a ) + 1];

    size_t i = 0;
    do
    {
        b[i] = std::tolower( static_cast<unsigned char>( a[i] ) );
    } while ( a[i++] );   

    return b;
}

函数设计假设函数的客户端必须释放返回的指针指向的内存。

【讨论】:

  • 投射到unsigned char?这比原来的还差。它只会隐藏不正确的输入。
  • @SomeWittyUsername 你应该阅读下面的函数描述。这是功能的要求。
  • 你应该看看函数签名。它接受int。如果输入超出unsigned char 范围,则行为将未定义。如果用户提供了错误的输入,将其转换为 unsigned char 不会修复它,而是隐藏原始错误并使其更难调试。
  • @SomeWittyUsername 在我看来,标准中清楚地写着“在所有情况下,参数都是一个 int,其值应表示为无符号字符或应等于宏的值EOF。如果参数有任何其他值,则行为未定义。"
  • 这与您建议的解决方案无关。该函数应该假设输入是正确的,或者如果输入不正确则将其处理到位,而无需进行一些奇怪的尝试来“修复它”以避免未定义的tolower 行为。例如,处理可以是断言或抛出异常或返回 NULL 作为输出。
【解决方案3】:

您的示例代码确实是 C++ 代码,但它不是真正的 C++ 代码。

最近的 C++11(或 C++14)倾向于不鼓励编写这样的东西。你可能想使用smart pointers, RAII idioms, rule of five, std::string-s,

当然,在进行显式手动内存分配的语言和程序中,您需要约定和规则来定义应该释放指针的人员和时间。对于您的代码,您至少需要在头文件中添加一条注释,说明应该发布lowerCaseWord 函数的结果的人员、方式和时间。

我认为您至少应该阅读有关 garbage collectionreference counting 的内容(至少对于概念和术语而言)。

【讨论】:

    【解决方案4】:

    智能指针是一种解决方案,但我建议您将函数更改为:

    void lowerCaseWord(char* destination, const char* source);
    

    使用此定义,调用者负责为目标字符串分配和释放内存。这样做的好处是目标可以在堆栈上、堆上,甚至是类/结构的成员。如果内存总是由函数分配,这是不可能的。

    strcpy和朋友也是这样定义的。

    【讨论】:

      猜你喜欢
      • 2015-09-23
      • 2013-12-27
      • 1970-01-01
      • 2011-06-17
      • 1970-01-01
      • 1970-01-01
      • 2015-01-18
      • 1970-01-01
      • 2019-09-17
      相关资源
      最近更新 更多