我在堆或堆栈中使用CString吗?如何将它与堆内存一起使用?

时间:2014-02-11 12:57:00

标签: c++ memory-management stack heap cstring

我正在使用VS2012。我宁愿为堆中的CString分配内存,所以给出下面的代码:

  1. CString csToken是从堆栈还是分配内存?
  2. 我是否需要释放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;
    

3 个答案:

答案 0 :(得分:2)

一旦函数超出范围,将释放在堆栈上分配的任何内容。必须明确释放堆上的任何内容。

csToken尚未使用new关键字进行分配,因此它位于堆栈中,而不是堆中。

最后,我发现你使用的是C ++,在C ++中使用free()malloc()是非常忌讳的。您应该使用newdelete关键字。

编辑:

这一行可以改写:

TCHAR *sAllCodes = (TCHAR *) calloc(50000,sizeof(TCHAR));

为:

TCHAR *sAllCodes = new TCHAR(5000);

这是使用new关键字的方法。

答案 1 :(得分:2)

  1. CString csToken变量在堆栈上分配,但是一旦为其分配了一些字符串,它就会在堆上分配其内部缓冲区。

  2. 您不需要释放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 ++异常,在sAllCodessCode堆上分配的内存将被释放。

更现代的更实用的 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());