何时删除返回值的分配内存

Posted

技术标签:

【中文标题】何时删除返回值的分配内存【英文标题】: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 :) 【参考方案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 字符处理)

    ...在所有情况下,参数都是一个 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 collection 和 reference counting 的内容(至少对于概念和术语而言)。

【讨论】:

【参考方案4】:

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

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

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

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

【讨论】:

以上是关于何时删除返回值的分配内存的主要内容,如果未能解决你的问题,请参考以下文章

何时为变量分配内存,在声明时还是在初始化时?

何时使用 alloca 为类成员分配内存?

何时为 C++ 中的类的成员函数分配内存空间?

TSQL 何时为存储过程中的变量(和表变量)分配内存

何时在声明或初始化时为变量分配内存?

堆栈指针的内存分配