【发布时间】:2012-06-15 04:21:13
【问题描述】:
我从一个非常简单的程序开始:
#include <TBString.h>
int main(int argv, char** argc)
{
tb::String test("");
test = "Hello World!";
return 0;
}
tb::String 是我自己的字符串类,旨在处理char 字符串和wchar_t (Unicode) 字符串。它是大量模板化的,tb::String 是 tb::StringBase<char> 的 typedef。
整个过程是使用 CRT 调试实用程序编译的,以检查内存泄漏。这是输出:
Detected memory leaks!
Dumping objects ->
c:\users\sam\svn\dependencies\toolbox\headers\tbstring2.inl(38) : {442} normal block at 0x00D78290, 1 bytes long.
Data: < > 00
{131} normal block at 0x00C5EFA0, 52 bytes long.
Data: < > A0 EF C5 00 A0 EF C5 00 A0 EF C5 00 CD CD CD CD
Object dump complete.
Detected memory leaks!
Dumping objects ->
c:\users\sam\svn\dependencies\toolbox\headers\tbstring2.inl(38) : {442} normal block at 0x00D78290, 1 bytes long.
Data: < > 00
Object dump complete.
The program '[2888] SAM_release.exe: Native' has exited with code 0 (0x0).
所以看起来像一个空的 tb::String(大小为 0)正在导致内存泄漏。用这个程序确认,不会泄露:
#include <TBString.h>
int main(int argv, char** argc)
{
tb::String test("Hello World!");
return 0;
}
原程序的调用栈:
- 使用字符串
""创建一个StringBase<char>。 -
m_Length设置为 0。 -
m_Maximum设置为m_Length + 1(1)。 -
m_Data的长度为m_Maximum(1)。 -
m_Data被清除并用""填充。 -
_AppendSingle设置为StringBase<char>::_AppendDynSingle。 - 使用字符串
"Hello World!"调用重载运算符StringBase<char>::operator = -
_AppendSingle被调用。 -
m_Length为 0,m_Maximum为 1。 -
checklen设置为m_Length + src_len + 1(13)。 -
m_Maximum乘以 2 直到大于checklen(16)。 -
StringBase<char>::Resize函数以新的最大值调用。
调整大小功能:
template <typename C>
TB_INLINE StringBase<C>& StringBase<C>::Resize(int a_Maximum /*= -1*/)
{
if (!m_Data)
{
m_Maximum = (a_Maximum == -1) ? 4 : a_Maximum;
m_Data = new C[m_Maximum];
StringHelper::Clear<C>(m_Data, m_Maximum);
}
else
{
int newmax = (a_Maximum == -1) ? (m_Maximum * 2) : a_Maximum;
C* temp = new C[newmax];
StringHelper::Clear<C>(temp, newmax);
if (m_Length > 0) { StringHelper::Copy(temp, m_Data, m_Length); }
delete [] m_Data;
m_Data = temp;
m_Maximum = newmax;
}
return *this;
}
这是我怀疑的问题。现在,我的问题变成了:
如何在 C++ 中重新分配内存而不触发 CRT 调试器中的内存泄漏?
构造函数:
TB_INLINE StringBase<char>::StringBase(const char* a_String)
{
m_Length = StringHelper::GetLength<char>(a_String);
m_Maximum = m_Length + 1;
m_Data = new char[m_Maximum];
StringHelper::Clear<char>(m_Data, m_Maximum);
StringHelper::Copy<char, char>(m_Data, a_String, m_Length);
_AppendSingle = &StringBase<char>::_AppendDynSingle;
_AppendDouble = &StringBase<char>::_AppendDynDouble;
}
析构函数:
TB_INLINE StringBase<char>::~StringBase()
{
if (m_Data) { delete [] m_Data; }
}
赋值运算符:
TB_INLINE StringBase<char>& StringBase<char>::operator = (const char *a_String)
{
Clear();
return (this->*_AppendSingle)(a_String);
}
附加函数:
template<>
TB_INLINE StringBase<char>& StringBase<char>::_AppendDynSingle(const char* a_String)
{
if (!a_String) { return *this; }
int src_len = StringHelper::GetLength<char>(a_String);
// check size
if (m_Maximum == -1)
{
m_Maximum = src_len + 1;
m_Data = new char[m_Maximum];
StringHelper::Clear<char>(m_Data, m_Maximum);
m_Length = 0;
}
int checklen = m_Length + src_len + 1;
if (checklen > m_Maximum)
{
while (checklen > m_Maximum) { m_Maximum *= 2; }
Resize(m_Maximum);
}
// append
strcat(m_Data, a_String);
// new length
m_Length += src_len;
return *this;
}
请注意:我不想使用std::string 或std::vector,我想修复这个功能。
【问题讨论】:
-
这个问题似乎主要与
tb::String类有关。这是你现在自己的还是来自某个图书馆的? -
什么是
tb::String?是什么严重的事情,还是你搞砸了? -
@user1240436 -1。在数组上使用
delete ptr会导致堆损坏。 -
@KonradRudolph - 有很多借口:您正在编写自己的智能指针类;您使用的是 C++98 之前的编译器;您正在编写嵌入式(独立式)应用程序;或者你只是想获得一些指针的乐趣!
-
@rodrigo 再次阅读我的评论,我说“在你的代码中”。我专门指的是 OP 的用例。我同意嵌入式环境,但这反对使用
delete,而不是反对智能指针。而指针乐趣并不是一个严肃的应用程序。但即使在一般情况下,我也看不出这少数极端情况如何成为“许多借口”。
标签: c++ memory-leaks dynamic-allocation