c++ - 这是将 CString 与堆还是堆栈一起使用?我如何将它与堆内存一起使用?

标签 c++ memory-management heap-memory c-strings stack-memory

我正在使用 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;
    

最佳答案

你的 csToken变量是 CString 的实例分配在堆栈上,因此您无需执行任何操作即可删除它:它的析构函数将在该变量的范围终止时进行适当的字符串清理。

然而,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()成员函数。

如果要将初始 vector 内容设置为全0,可以使用vector v(count, 0)构造函数重载。

使用 C++ 风格的转换

在你的代码中你有一个 C 风格的 (DWORD) throw 。 C 风格的转换不好;考虑改用C++ 风格的转换。在您的情况下,您可能需要 static_cast<DWORD>(...) .

使用 CString::IsEmpty()提高可读性

你的代码中有一个 if 是这样的:

if (vAllCodes[i].StringLength() > 0)

CString提供方便IsEmpty()方法,更具可读性:

if (! vAllCodes[i].IsEmpty()) 
    ....

关于 _stprintf_s() 的注释和“魔数(Magic Number)”

您使用 _stprintf_s()像这样:

_stprintf_s(sCode,128,L"%s",vAllCodes[i].GetString()); 

但请注意,如果您使用 TCHAR模型,为了连贯你应该使用 _T("%s") 在格式说明符中。
如果您只想使用 Unicode 字符串和 L"%s" (我建议),然后使用相应的 Unicode-only swprintf_s() ,并去掉 TCHAR只需使用 wchar_t 代替。

另请注意,您可能希望使用 sCode.size() 而不是使用“魔数(Magic Number)”128 (假设 sCode 成为 std::vector 的实例,正如我上面所建议的)。所以,如果你改变 vector 的大小,你不必更新“魔数(Magic Number)”128(有了这些魔数(Magic Number),基本上会有错误等待发生:)
更新后的代码可能类似于:

swprintf_s(code.data(), code.size(), L"%s", vAllCodes[i].GetString()); 

关于c++ - 这是将 CString 与堆还是堆栈一起使用?我如何将它与堆内存一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21702473/

相关文章:

java - Scanner 类的 .next() 方法中的 String 值在内存中分配在哪里?

java - 我们要在catalina.sh中为JAVA_OPTS设置多少内存

java - 在 OutOfMemoryError Linux 上自动重启 jar

c++ - 如何在没有焦点的情况下更新 QDataWidgetMapper 项目

c++ - 候选模板被忽略 : couldn't infer template argument

c++ - 跳过每三个数字

Android 不从内存中释放位图

c# - 如何在不内存溢出的情况下按需访问数千张图像

c++ - 如何将 CAPI 的 CryptImportKey 与来自 OpenSSL 的 PEM 编码公钥一起使用?

arrays - Fortran 函数返回数组时的最佳实践是什么?