Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

General Question: CString vs LPTSTR & LPCTSTR

1,364 views
Skip to first unread message

JCO

unread,
May 12, 2010, 10:36:09 AM5/12/10
to
As I get back into MFC Coding, I'm reminded of the different data types that
can be used for proper & efficient coding. Generally, I see functions that
use LPTSTR & LPCTSTR. I'm wondering why the CString is not used as much as
a parameter. If you pass "CString &", of course, it would be efficient as
compared to passing the entire CString class.

My understanding it that
LPSTR == char*
LPCSTR == const char*

Then you can throw your "T" in for Unicode conversion.
LPTSTR == LPWSTR or LPSTR
LPCTSTR == LPCWSTR or LPCSTR

I'm confused as to why these seem to be the most popular parameter types.
Typically I convert these types to a local CString in a function .. .then do
my work. Is this okay?

Thanks

Giovanni Dicanio

unread,
May 12, 2010, 11:36:57 AM5/12/10
to
"JCO" <som...@somewhere.com> ha scritto nel messaggio
news:ux4k3Be8...@TK2MSFTNGP05.phx.gbl...

> As I get back into MFC Coding, I'm reminded of the different data types
> that can be used for proper & efficient coding. Generally, I see
> functions that use LPTSTR & LPCTSTR. I'm wondering why the CString is not
> used as much as a parameter. If you pass "CString &", of course, it would
> be efficient as compared to passing the entire CString class.

The equivalence would be between LPCTSTR (i.e. 'const TCHAR *') and 'const
CString &'.

If you pass strings as read-only parameters to a function or method, I would
suggest to use LPCTSTR (i.e. 'const TCHAR *').
This way, you could pass both a string literal (without creating a new
temporary instance of CString) and a CString instance (in fact, there is an
implicit LPCTSTR conversion operator defined for the CString class).

Instead, if you want to pass modifyable string parameters, then I would
suggest to use 'CString &'.

If you return a string from a function or a method, I would suggest to just
pass an instance of CString.

e.g.

CString DoSomethingAndReturnString(
LPCTSTR psz // [input] const TCHAR *
CString & str // [input/output] reference to CString
);


> I'm confused as to why these seem to be the most popular parameter types.

You may want to read:

CString Argument Passing
http://msdn.microsoft.com/en-us/library/acttytz3(v=VS.80).aspx


Giovanni

Goran

unread,
May 12, 2010, 12:38:59 PM5/12/10
to
On May 12, 4:36 pm, "JCO" <some...@somewhere.com> wrote:
> As I get back into MFC Coding, I'm reminded of the different data types that
> can be used for proper & efficient coding.  Generally, I see functions that
> use LPTSTR & LPCTSTR.  I'm wondering why the CString is not used as much as
> a parameter.  If you pass "CString &", of course, it would be efficient as
> compared to passing the entire CString class.

That is correct. In context of MFC it is normally a major performance
fault to pass LPCTSTR around, because of e.g. this:

f(LPCTSTR param)
{
CString s(param); // Allocation!
// or similar use.
}

CString s = ...;
f(s);

Compare this to:
f(const CString& param)
{
CString s(param); // NO ALLOCATION, I win.
}

CString s = ...;
f(s);

In other words, one should use LPCTSTR only when sure that it will not
be converted to a CString, or somehow mixed with one, somewhere down
the line. And that's typically a tall order.

Goran.

Joseph M. Newcomer

unread,
May 13, 2010, 1:37:42 AM5/13/10
to
It is a popular parameter type because it is "POD" (Plain Old Data). Therefore, functions
that use LPCTSTR can be used by both C callers and C++ callers. If you are in MFC,
Giovanni has already pointed out the issues, which is you really want to use const
CString& most of the time. Remember that a lot of the people writing this code learned to
write C code first and never outgrew the bad habits they developed then. But the API
calls use LPCTSTR because they have to be compatible with C programmers as well.

You should never pass a parameter as non-const if it is never modified. The const
qualifier helps users identify if the string passed will be modified or not, and also the
compiler can produce slightly better code if a const is involved. But the documentation
value of const is far more important.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Hector Santos

unread,
May 13, 2010, 3:55:54 AM5/13/10
to
I think a key point for the OP to understand that I didn't see pointed
out is that the CString object has a LPCTSTR (const char *) overload
operator to return a pointer to the CString internal asciiz string
(null terminated string) buffer.

--
HLS

JCO

unread,
May 13, 2010, 8:32:18 PM5/13/10
to
Whats the purpose of passing a "const CString &"?
I will read the article.. thanks
Any reason why you would prefer to use "const TCHAR" over "const CString &"
in your function parameters?

"Giovanni Dicanio" <giovanniD...@REMOVEMEgmail.com> wrote in message
news:#y804je8...@TK2MSFTNGP04.phx.gbl...

JCO

unread,
May 13, 2010, 9:00:52 PM5/13/10
to
Yes I saw that. Thanks

"Hector Santos" <sant...@gmail.com> wrote in message
news:hsgbb3$1epm$1...@news.ett.com.ua...

JCO

unread,
May 13, 2010, 9:04:18 PM5/13/10
to
It really sounds like (for MFC) it's better to completely stay away from
LPCTSTR & TCHAR.
Use CString, CString& or similarly with the "const" in front for Read Only.

"Goran" <goran...@gmail.com> wrote in message
news:ca32288f-04d8-49e3...@n15g2000yqf.googlegroups.com...

Joseph M. Newcomer

unread,
May 13, 2010, 11:27:43 PM5/13/10
to
See below...

On Thu, 13 May 2010 19:32:18 -0500, "JCO" <som...@somewhere.com> wrote:

>Whats the purpose of passing a "const CString &"?
>I will read the article.. thanks
>Any reason why you would prefer to use "const TCHAR" over "const CString &"
>in your function parameters?

****
I presume you mean "const TCHAR *", because "const TCHAR" is a simple scalar value which
is nominally sizeof(TCHAR) but is more likely 32 bits because of how parameters are
passed.

But a const TCHAR * can accept any constant string pointer, whereas "const CString &" can
only accept a CString. So if you pass _T("abc"), it will actually call the CString
constructor to create a CString object to pass in.

When I'm programming in MFC, I almost never have a data type OTHER than CString, so I tend
to use const CString & when I'm working within my native framework. I rarely have a raw
string literal in such cases, and in the extremely rare cases I do, I don't really care
about the constructor cost.
joe

Goran

unread,
May 14, 2010, 2:47:43 AM5/14/10
to
On May 14, 3:04 am, "JCO" <some...@somewhere.com> wrote:
> It really sounds like (for MFC) it's better to completely stay away from
> LPCTSTR & TCHAR.

Pretty much, yeah. At any rate, whenever you have a CString, and you
interact with a C API that has C string parameter, you'll either go
through directly through CString's "C string" conversion operators
(see operator PCXSTR in CString), or you will be forced to use one of
"buffer" routines for non-const params.

> Use CString, CString& or similarly with the "const" in front for Read Only.

Yes. It's not "Read only", it's more "input", really. Normally, you
really rarely want to use plain CString. You want that when you want
to pass it as an input (by value), and you want to modify it inside,
e.g. (warning: hugely contrived example):

void f(CString s)
{
if (whatever) s = val1; else s = val2;
someOtherFunc(s);
}

But that's just the same as:

void f(const CString& s)
{
CString local(s)
if (whatever) local = val1; else local = val2;
someOtherFunc(s);
}

(BTW, I bet you that you won't be able to see performance difference
in an optimized build between the two versions, and it's even possible
that compiler will compile the two to the exact same code).

As Joe said, using const for "input" parameters has a good
"documentation" value. I wonder if this will ever become a part of
typical coding guidelines for C and C++ (it should have, by now, but C
is an old language, and if it still isn't there for C code, so chances
of that ever happening are slim).

Goran.

Hector Santos

unread,
May 14, 2010, 3:13:01 AM5/14/10
to
JCO wrote:

> It really sounds like (for MFC) it's better to completely stay away from
> LPCTSTR & TCHAR.
> Use CString, CString& or similarly with the "const" in front for Read Only.


Yes, if you wish to ignore any performance lost due to the extra
overhead. But today's computers are fast so who cares? :)

But the other thing is issues may rear its ugly head when you are
passing it across boundaries, like between the exe and dlls.

For example, if you put your functions in a DLL, now they are highly
dependent on MFC being included in the DLL when it might have to be if
you are using passing a const string pointer and can work with it with
out needing the help from CString member functions.

You shouldn't have problems but you have to keep it in the back of
your mind for any heap related issues.

--
HLS

JCO

unread,
May 14, 2010, 4:13:32 PM5/14/10
to
Got it....thanks

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:7jgpu5h5t6vkdm4iu...@4ax.com...

John H.

unread,
May 14, 2010, 5:01:15 PM5/14/10
to
Goran wrote:
> On May 14, 3:04 am, "JCO" <some...@somewhere.com> wrote:
> > Use CString, CString& or similarly with the "const" in front for Read Only.
>
> Yes. It's not "Read only", it's more "input", really. Normally, you
> really rarely want to use plain CString. You want that when you want
> to pass it as an input (by value), and you want to modify it inside,

Although probably a rare case, but in a multithreaded app, the
difference between CString and CString const & could be important.
e.g.

// Global resource:
CString csName("Albert");

// Thread 1:
...
DoSomething(csName); // line 1
...

// Thread 2:
...
csName = "Alex"; // line 2
...

Now consider if DoSomething is defined as
void DoSomething(CString csFriend)
{
...
cout << csFriend<< endl; // line 3
}

Now consider line1 begins execution, and the name "Albert" is copied
into the csFriend argument. Then control switches to thread 2 and
line 2 is executed. Then control goes back to thread 1 and line 3 is
executed. "Albert" will be printed.

If on the other hand DoSomething is defined with reference:
void DoSomething(CString const & csFriend)
{
...
cout << csFriend<< endl; // line 3
}

With the same serious of executions steps, "Alex" would be printed.

Depending on what you are trying to do, either one could be the
desired behavior.

JCO

unread,
May 14, 2010, 5:37:20 PM5/14/10
to
I certainly understand when to use CString vs CString (and conversely using
const).
My original thread pertained concerns over LPTSTR, LPCTSTR (along with
TCHAR).... I plan to avoid this if posible.
Thanks

"John H." <oldman_...@yahoo.com> wrote in message
news:2c44a0ec-d68b-4a3a...@s41g2000vba.googlegroups.com...

Goran

unread,
May 16, 2010, 4:12:57 AM5/16/10
to

Well, that is true, but the problem is at a much lower level: code is
attempting to read/write a shared datum from multiple threads. That
does not work in a general case. Your example just muddies the waters
and tries to apply them to a CString&.

Goran.

Joseph M. Newcomer

unread,
May 17, 2010, 1:00:14 AM5/17/10
to
const is a keyword in the C language, and therefore can be used in C programming!

It is not specific to C++.

Recently, I added a bunch of const declarations to a C- based library; we actually
uncovered some errors as a consequence! For example, there was a function that modified
an input string by writing into it, and this would have failed if a literal string was
passed in! (The result, because literal strings are placed in read-only memory, would
have been an access fault; and when I reported this, the response was "Yeah, we had some
tech support calls on that which we now understand")
joe

Joseph M. Newcomer

unread,
May 17, 2010, 1:05:00 AM5/17/10
to
Under any possible scenario, the code you show has to be incorrect. You may not under any
cirucmstances modify a global variable in that fashion; in fact, the code is incorrect if
the global variable is an int. In the case of the CString, the integrity of the data
value itself can be compromised, and the code would be incorrect at a deep level without
locking. With locking, it is still incorrect at the superficial level. So arguming about
CString or its value is meaningless; if the variable was an LPTSTR the code would still be
wrong.
joe

****
Anyone reading this code would realize that independent of the parameter type or the
copy-on-write semantics of CString, these is nothing right about the above code.
joe
****

Joseph M. Newcomer

unread,
May 17, 2010, 1:10:17 AM5/17/10
to
See below...

On Fri, 14 May 2010 03:13:01 -0400, Hector Santos <sant...@gmail.com> wrote:

>JCO wrote:
>
>> It really sounds like (for MFC) it's better to completely stay away from
>> LPCTSTR & TCHAR.
>> Use CString, CString& or similarly with the "const" in front for Read Only.
>
>
>Yes, if you wish to ignore any performance lost due to the extra
>overhead. But today's computers are fast so who cares? :)

****
No only that, but statistically the time is insignificant in nearly all cases. If this
were happening billions of times in an inner loop, the time might become statistically
significant.
****


>
>But the other thing is issues may rear its ugly head when you are
>passing it across boundaries, like between the exe and dlls.
>
>For example, if you put your functions in a DLL, now they are highly
>dependent on MFC being included in the DLL when it might have to be if
>you are using passing a const string pointer and can work with it with
>out needing the help from CString member functions.

****
I always assume a shared MFC DLL. The DLL runtime issue is one of the ugly secrets of C++
programming that Nobody Talks About, like the weird uncle at a family gathering. But as
soon as you have separate runtimes (static linking) all bets are off, not only for CString
but for all MFC structures. At that point, your problems are so serious that the impact
on CString is hardly noticeable; it is usually just the first victim of this problem.
****


>
>You shouldn't have problems but you have to keep it in the back of
>your mind for any heap related issues.

****
The same problem applies to the C runtime library with malloc and free. It is not unique
to C++ or MFC runtimes. A simple LPTSTR can fail just as badly.

0 new messages