在我自己的字符串类中(仅用于学习)我有运算符+的重载
我是否需要清除tmpPtr
指向的内存?
String String::operator+(const String& rv) const
{
size_t newLength = length + rv.length;
char* tmpPtr = new char[newLength + 1];
strcpy(tmpPtr, ptr);
strcpy(tmpPtr + length, rv.ptr);
String S(tmpPtr);
delete[] tmpPtr;
return S;
}
我可以这样改变这种方法吗?
String String::operator+(const String& rv) const
{
size_t newLength = length + rv.length;
char* tmpPtr = new char[newLength + 1];
strcpy(tmpPtr, ptr);
strcpy(tmpPtr + length, rv.ptr);
return S(tmpPtr);
}
如果有人需要构造函数和析构函数:
String::String(const char* str)
{
setString(str, strlen(str));
}
String::String(const String& str)
{
setString(str.ptr, str.length);
}
void String::setString(const char* str, size_t size)
{
ptr = new char[size + 1];
strcpy(ptr, str);
length = size;
}
String::~String()
{
delete[] ptr;
}
答案 0 :(得分:2)
正如Vlad所说,这取决于你如何实现构造函数。
如果构造函数只是获取指针的所有权,然后在析构函数中删除它,那么这里不需要delete[]
。但是,这是有问题的,因为这意味着您无法直接从字符串文字中安全地构造String
实例。
通常,编写构造函数的更好方法是将传入指针的内容复制到新的内存块,然后存储指向该内存的指针。这意味着String
的内存使用是对称的:它释放它分配的所有内容,而不是其他内容。这意味着,如果您new[]
某个内容然后将该指针传递给String
的构造函数,则仍需要delete[]
它。
然而,无论哪种方式,这两种选择都不是特别适合。相反,你应该做这样的事情:
String String::operator+(const String& rv) const
{
size_t newLength = length + rv.length;
// Create a string with enough backing storage
String S(newLength + 1);
strcpy(S.ptr, ptr);
strcpy(S.Ptr + length, rv.ptr);
return S;
}
这确保它是管理所涉及内存的String
实例,因此您可以获得通常从构造函数/析构函数对获得的所有清理保证。
编辑:在构造函数的主体可用的情况下,我们可以得出结论,您采用了第二种方法。因此,如果您继续使用此方法,则执行需要delete[]
内存。
答案 1 :(得分:1)
是。通常,您需要删除new
分配的内存。
Wiki说:
在C ++编程语言中,
delete
运算符调用给定参数的析构函数,并将new
分配的内存返回给堆。[1]每次调用delete
时都必须调用new
以避免内存泄漏。
.....如果没有对析构函数的显式调用,或者如果没有使用 delete-expression (5.3.5)来释放存储,则不应该隐式调用析构函数并且任何依赖于析构函数产生的副作用的程序都有未定义的行为。
编辑:根据OP的编辑,由于析构函数正在释放内存,在这种情况下无需明确删除ptr
。但仍需要使用tmpPtr
运算符删除delete[]
。
答案 2 :(得分:1)
由于构造函数String::setString
调用的String::String
成员函数在动态内存中创建了自己的char数组,并复制了传递的字符串的内容:
void String::setString(const char* str, size_t size)
{
ptr = new char[size + 1];
strcpy(ptr, str);
length = size;
}
不再需要String::operator+
中最初创建的内存,无法存储,因此如果不删除则会泄漏。所以,是的,你必须delete[]
。