何时删除返回值的分配内存
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<char>
是单个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
和朋友也是这样定义的。
【讨论】:
以上是关于何时删除返回值的分配内存的主要内容,如果未能解决你的问题,请参考以下文章