管理CStringArray条目
这是在VisualStudioMFC应用程序的上下文中管理CStringArray条目,string,mfc,String,Mfc,这是在VisualStudioMFC应用程序的上下文中 CStringArray::Add()成员接受一个LPCTSTR参数。如果我使用CString参数,我假定CString的LPCTSTR操作符将Add()的CString参数隐式转换为LPCTSTR,因此如果我有CStringArray arr和CString s并调用arr.Add(s),这与调用arr.Add((LPCTSTR)s)完全相同,对吗 所以,当调用Add()时,CStringArray是简单地存储传递的指针,还是单独复制字符
CStringArray::Add()
成员接受一个LPCTSTR
参数。如果我使用CString
参数,我假定CString
的LPCTSTR
操作符将Add()
的CString
参数隐式转换为LPCTSTR
,因此如果我有CStringArray arr
和CString s
并调用arr.Add(s)
,这与调用arr.Add((LPCTSTR)s)
完全相同,对吗
所以,当调用Add()
时,CStringArray
是简单地存储传递的指针,还是单独复制字符串并存储它?我这样问是因为我想知道在添加字符串时是否必须创建一个持久字符串,或者在添加后是否可以删除我的字符串。例如,以下哪项是正确的
class MyClass :
{
...
CStringArray arr;
CString mystr;
void foo1() { arr.Add(_T("Bippety")); }
void foo2() { CString s(_T("Boppety"); arr.Add(s); }
void foo3() { mystr = _T("Boop"); arr.Add(mystr); }
...
};
让我担心的是,在foo1()
和foo2()
返回之后,传递的参数超出范围并被删除。那么,数组是保存自己的副本,还是保存无效指针
CStringArray
中存储的数据只是一个指针,还是在调用Add()
时,它实际上甚至创建了一个CString
最后,如果我将LPCTSTR
传递给add,那么我假设如果我通过调用new
来创建字符串来添加它,那么我肯定要负责delete
在CStringArray
被销毁之前将其删除,对吗
我只是不太明白当它只是一个本地字符串时,
LPCTSTR
如何在CStringArray
中生存。CStringArray
是一个存储C字符串的MFC类型数组。如果使用Unicode编译,CString
是一个CStringW
,如果为MBCS编译,CString
是一个CStringA
本课程的重点是,您不必太担心内存管理。它是为你做的。将LPCTSTR
类型字符串传递给数组时,它将构造一个CString
对象并将其添加到数组中。当CStringArray
对象超出范围和/或调用其析构函数时,它所持有的所有cstring都将被清除
然而,有一个警告
CString
类是或多或少计数的引用。它有一个内部类,当你复制一个类时,它不会复制所有的数据。相反,它添加了对一些内部结构的引用并使用它。如果您执行了一些更改数据的操作,那么它会将自身与引用分离,并设置自己的新数据结构。您必须单步通过代码才能看到这一点
现在,CStringArray
有两个Add()
方法。一个接受一个LPCTSTR
另一个接受一个const CString&
。第二个复制了CString
,进行上一段中提到的准参考计数
这只是补充信息。使用CStringArray
,您真的不必过于担心内存管理问题。它为你做了繁重的工作
你唯一需要担心的是引用计数,如果你做了一些愚蠢的事情而忽略了常量
考虑以下代码:
#include <afx.h>
#include <stdio.h>
void main()
{
CString s("HERE is my string\n");
CStringArray sArray;
sArray.Add(s);
sArray.Add(s);
_tprintf((LPCTSTR) s); // "HERE is my string"
_tprintf((LPCTSTR) sArray[0]); // "HERE is my string"
_tprintf((LPCTSTR) sArray[1]); // "HERE is my string"
sArray[0].MakeLower();
_tprintf((LPCTSTR) s); // "HERE is my string"
_tprintf((LPCTSTR) sArray[0]); // "here is my string"
_tprintf((LPCTSTR) sArray[1]); // "HERE is my string"
LPCTSTR lpsz = sArray[1];
_tcsupr((LPTSTR) lpsz); // don't do it!!!, also changes s!!!
_tprintf((LPCTSTR) s); // "HERE IS MY STRING"
_tprintf((LPCTSTR) sArray[0]); // "here is my string"
_tprintf((LPCTSTR) sArray[1]); // "HERE IS MY STRING"
}
#包括
#包括
void main()
{
CString s(“这是我的字符串\n”);
CStringArray;
sArray。添加(s);
sArray。添加(s);
_tprintf((LPCTSTR)s);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[0]);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[1]);/“这是我的字符串”
sArray[0]。MakeLower();
_tprintf((LPCTSTR)s);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[0]);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[1]);/“这是我的字符串”
LPCTSTR lpsz=sArray[1];
_tcsupr((LPTSTR)lpsz);//不要这样做!!!,也会更改s!!!
_tprintf((LPCTSTR)s);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[0]);/“这是我的字符串”
_tprintf((LPCTSTR)sArray[1]);/“这是我的字符串”
}
如果您查看第三个分组的打印输出,您会发现当我们为调用\u tcsupr
(strupr
)将lpsz强制转换为非常量字符串时,违反了常量。由于MFC引用计数字符串的方式,“s”字符串内容也会受到影响。在第二个分组调用CString
的MakeLower()
成员函数的情况下,只有该特定字符串有效
这比你要求的要多。也许这对人们会有帮助。为什么不调试Add调用?这将带您了解源代码。@AndrewTruckle:我不知道源代码是可用的。我以为它只是一个库。如果你使用调试模式,那么它将进入源文件。@AndrewTruckle:好的,非常好。我看到它最终使用memcpy()
创建参数所指向字符串的私有副本。这就回答了所有问题,谢谢+调试配置并不是进入MFC源代码的严格要求。MFC版本的Microsoft host debug symbols也构建在它们的公共符号服务器上。CStringT
类模板有一个专用接口,用于修改和更新内部字符缓冲区(GetBuffer()
和friends)。如果您在其规范之外使用CStringT
,则一切都会发生。因为没有明显的理由这么做,所以解决办法很简单:不要。我不得不在一位同事离开后修复他工作中的一个bug。他抛弃了字符串的常量,将其传递给一个采用LPTSTR的API…你知道什么…它引入了一个bug…令人震惊,对吗?