我正在使用VS2012。我宁愿为堆中的CString分配内存,所以给出下面的代码:
我是否需要释放csToken正在使用的内存,或者它是否会在函数终止时自动释放?
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR)); // Dynamically use Heap memory to hold all pipe-delimited codes
TCHAR *sCode = (TCHAR *) calloc(128,sizeof(TCHAR)); // Dynamically use Heap memory to hold a single code
DWORD i = 0;
LoadAllCodes(&sAllCodes); // Custom function
CString csToken; // Declare the CString variable
csToken.Append(sAllCodes); // Assign the string to the Cstring variable
vector<CString> vAllCodes; // Declare the vector variable
vAllCodes = Split(csToken,L"|"); // Split the CString into a vector array
while ( i < (DWORD) vAllCodes.size())
{
if (vAllCodes[i].StringLength() > 0) // If there is a string in the vector item
{
_stprintf_s(sCode,128,L"%s",vAllCodes[i].GetString()); // Get the vector item and copy it into a string
// Do work on sCode here...
}
i++;
}
free(sAllCodes);sAllCodes=NULL;
free(sCode);sCode=NULL;
答案 0 :(得分:2)
一旦函数超出范围,将释放在堆栈上分配的任何内容。必须明确释放堆上的任何内容。
csToken
尚未使用new
关键字进行分配,因此它位于堆栈中,而不是堆中。
最后,我发现你使用的是C ++,在C ++中使用free()
和malloc()
是非常忌讳的。您应该使用new
和delete
关键字。
编辑:
这一行可以改写:
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR));
为:
TCHAR *sAllCodes = new TCHAR(5000);
这是使用new关键字的方法。
答案 1 :(得分:2)
CString csToken
变量在堆栈上分配,但是一旦为其分配了一些字符串,它就会在堆上分配其内部缓冲区。
您不需要释放csToken
明确占用的任何内存,一旦csToken
变量超出范围,它就会被释放,并且它的析构函数被调用。
答案 2 :(得分:2)
您的csToken
变量是堆栈上分配的CString
实例,因此您无需执行任何操作来删除它:析构函数< / em>将在此变量的作用域终止时进行正确的字符串清理。
但是,CString
内部维护对实际字符串的引用,该字符串在堆上分配。
CString
实际上使用 "COW" 技术和引用计数,因此多个CString
个实例可以共享相同的字符串,它们可以引用相同的字符串。但是,这些是CString
实施细节。
对于CString
的基本用法,“带走”的是,如果您有CString str
,则无需关注str
清理:它将是由CString
析构函数自动管理。
此外,我想利用这个机会,以改进它的精神为您的代码做一些注释。
使用std::vector
您在发布的代码顶部有这些分配:
TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR)); TCHAR *sCode = (TCHAR *) calloc(128,sizeof(TCHAR));
然后你在底部有相应的免费电话:
free(sAllCodes);sAllCodes=NULL; free(sCode);sCode=NULL;
但请注意,此代码不 异常安全:事实上,如果calloc()
和free()
来电之间的任何代码发生抛出一个C ++异常,在sAllCodes
和sCode
堆上分配的内存将不被释放。
在更现代的和更实用的 C ++风格中,您可以使用 std::vector
代替calloc()
来实现感谢std::vector
析构函数(就像CString
一样),在堆上分配内存,自动释放它。)
只需将calloc()
来电替换为:
std::vector<TCHAR> allCodes(50000);
std::vector<TCHAR> code(128);
然后删除free()
来电! :)
除了更简单和更短,您的代码也变得异常安全;事实上,如果抛出C ++异常,vector
析构函数将被自动调用,并释放已分配的内存。
如果您想访问vector
数据,可以使用其data()
成员函数。
如果要将初始矢量内容设置为全0,可以使用vector v(count, 0)
构造函数重载。
使用C ++风格的演员阵容
在您的代码中,您有一个C风格的(DWORD)
演员阵容。 C风格的演员阵容坏;考虑使用 C ++ - 样式转换。在您的情况下,您可能需要static_cast<DWORD>(...)
。
使用CString::IsEmpty()
提高可读性
你的代码中有一个if:
if (vAllCodes[i].StringLength() > 0)
CString
提供了一种方便的IsEmpty()
方法,更具可读性:
if (! vAllCodes[i].IsEmpty())
....
有关_stprintf_s()
和“幻数”的说明
您可以像这样使用_stprintf_s()
:
_stprintf_s(sCode,128,L"%s",vAllCodes[i].GetString());
但请注意,如果您使用 TCHAR
模型,为了保持一致性,您应该在格式说明符中使用 _T("%s")
。
如果您只想使用 Unicode 字符串和 L"%s"
(我建议),请使用相应的仅限Unicode swprintf_s()
< / strong>,摆脱TCHAR
,只需使用 wchar_t
。
另请注意,您可能希望使用sCode.size()
(假设sCode
成为std::vector
的实例,而不是使用“幻数”128 ,正如我上面所说的那样)。所以,如果你改变矢量的大小,你也不必更新“神奇数字”128(有了这些神奇的数字,基本上还有等待发生的错误:)
更新的代码可能类似于:
swprintf_s(code.data(), code.size(), L"%s", vAllCodes[i].GetString());