MPW
MPW

Reputation: 351

Managing CStringArray entries

This is in the context of a Visual Studio MFC application.

The CStringArray::Add() member takes an LPCTSTR argument. If I use a CString argument, I presume the argument is implicitly converted to LPCTSTR for Add() by the LPCTSTR operator of CString, so if I have a CStringArray arr and a CString s and call arr.Add(s), this is exactly the same as calling arr.Add((LPCTSTR)s), right?

So when Add() is called, does CStringArray simply store the passed pointer, or does it make a separate copy of the the string and store that? I'm asking because I wonder if I have to make a persistent string when I add it, or if my string can be deleted after it is added. For example, which if any of foo1(), foo2(), or foo3() is correct in the following?

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); }
    ...
};

The thing that worries me is that after foo1() and foo2() return, the passed argument goes out of scope and is deleted. Does the array then hold its own copy, or does it hold an invalid pointer?

Is the data stored in the CStringArray as just a pointer, or does it actually even go so far as to create a CString when Add() is called?

Finally, if I'm passing LPCTSTR to add, then I assume that if I created the string by a call to new to add it, then I'm surely responsible for deleteing it before CStringArray is destroyed, right?

I just can't quite see how the LPCTSTR can survive in the CStringArray when it's only a local string.

Upvotes: 2

Views: 1529

Answers (1)

Joseph Willcoxson
Joseph Willcoxson

Reputation: 6050

CStringArray is an MFC type array that stores CString's. If you compile with Unicode, the CString is a CStringW and if you compile for MBCS, the CString is a CStringA.

The point of the class is that you do not have to worry so much about memory management. It does it for you. When you pass an LPCTSTR type string to the array, it constructs a CString object and adds it to the array. When the CStringArray object goes out of scope and/or its destructor gets called, all the CStrings it is holding onto will be cleaned up.

However, there is a caveat...

The CString class is reference counted more or less. It has an internal class such that when you make a copy of a class, it doesn't copy all of the data. Instead, it adds a reference to some of the internal structures and uses that. If you do some operation that changes the data, then it detaches itself from the reference and sets up its own new data structures. You have to step through the code to see this.

Now, the CStringArray has two Add() methods. One takes an LPCTSTR the other a const CString&. The second one makes a copy of CString doing the quasi reference counting mentioned in the previous paragraph.

That is just added information. You really don't need to worry about memory management too hard with the CStringArray. It does the heavy lifting for you.

The only part where you have to worry about CString reference counting is if you do stupid stuff and ignore const.

Consider the following code:

#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"

}

If you look at the printout from the third grouping, you see that we violated const-ness when we cast lpsz to a non-const string for the call to _tcsupr (strupr). Because of the way MFC reference counts strings, the "s" string contents were also effected. In the case of the second grouping calling the MakeLower() member function of CString, only that particular string was effected.

This is more than you asked. Maybe it will be helpful to people.

Upvotes: 3

Related Questions