Figure 1 Passing Character Strings
class MyClass {
CString* m_str;
public:
MyClass();
~MyClass();
void SetLPCSTR( LPCSTR lpInputString );
LPCSTR GetLPCSTR( );
void SetCString( CString csInputString );
CString GetCString( );
};
MyClass::MyClass( )
{
m_str = NULL;
}
MyClass::~MyClass( )
{
if( m_str )
delete m_str;
}
LPCSTR MyClass::GetLPCSTR( )
{
CString csReturn;
if ( m_str )
csReturn = *m_str;
return csReturn;
}
void MyClass::SetLPCSTR( LPCSTR lpInputString )
{
if ( m_str == NULL )
m_str = new CString( lpInputString );
else
*m_str = lpInputString;
}
CString MyClass::GetCString( )
{
CString csReturn;
if ( m_str )
csReturn = *m_str;
return csReturn;
}
void MyClass::SetCString( CString csInputString )
{
if ( m_str == NULL )
m_str = new CString( csInputString );
else
*m_str = csInputString;
}
Figure 2 strtest.cpp
////////////////////////////////////////////////////////////////
// 1996 Microsoft Systems Journal.
// Written by Paul DiLascia
//
// STRTEST shows what function calls the compiler generates
// for various kinds of CString conversions and assignments.
//
// To see the code the compiler generates, type
//
// cl /c /Fa strtest.cpp
//
// and look at strtest.asm
//
#include <stdio.h>
typedef const char* LPCSTR;
//////////////////
// Stripped-down CString with outline functions instead of
// inline, to show what happens in the compiled code
//
class CString {
protected:
LPCSTR m_pchData; // pointer to string data
public:
CString();
CString(const CString& stringSrc);
CString(LPCSTR lpsz);
~CString();
operator LPCSTR() const;
const CString& operator= (const CString& cs);
const CString& operator= (LPCSTR lp);
};
//////////////////
// Some class with get/set methods to access a CString.
//
class MyClass {
CString m_str;
public:
void SetLPCSTR(LPCSTR lp);
LPCSTR GetLPCSTR();
void SetCString(const CString& cs);
const CString& GetCString();
};
////////////////
// In a real program, these functions would be inline.
// I left them "outline" so you can see where the
// compiler invokes them.
//
//
LPCSTR MyClass::GetLPCSTR()
{
return m_str; // invokes CString::operator LPCSTR();
}
const CString& MyClass::GetCString()
{
return m_str; // just return pointer to m_str;
}
void MyClass::SetLPCSTR(LPCSTR lp)
{
m_str = lp; // invokes CString::operator=(LPCSTR);
}
void MyClass::SetCString(const CString& cs)
{
m_str = cs; // invokes CString::operator= (const CString&)
}
void main()
{
MyClass foo;
CString cs = "this is a CString";
LPCSTR lp = "this is an LPCSTR";
// Four cases for set operation
foo.SetCString(cs); // case #1
foo.SetLPCSTR(cs); // case #2
foo.SetCString(lp); // case #3
foo.SetLPCSTR(lp); // case #4
// Four cases for get operation
cs = foo.GetCString(); // case #5
cs = foo.GetLPCSTR(); // case #6
lp = foo.GetCString(); // case #7
lp = foo.GetLPCSTR(); // case #8
}
Figure 3 strtest.asm
_main PROC NEAR
.
. prolog, initialization
.
;;================ Set functions ================
;; Case #1: foo.SetCString(cs);
;; -call SetCString (no conversion)
;;
lea eax, DWORD PTR _cs$[ebp]
push eax
lea ecx, DWORD PTR _foo$[ebp]
call ?SetCString@MyClass@@QAEXABVCString@@@Z ; MyClass::SetCString
;; Case #2: foo.SetLPCSTR(cs);
;; -first call operator LPCSTR to convert CString->LPCSTR
;; -call SetLPCSTR
;;
lea ecx, DWORD PTR _cs$[ebp]
call ??BCString@@QBEPBDXZ ; CString::operator LPCSTR
push eax
lea ecx, DWORD PTR _foo$[ebp]
call ?SetLPCSTR@MyClass@@QAEXPBD@Z ; MyClass::SetLPCSTR
;; Case #3: foo.SetCString(lp);
;; -first create temp CString T520
;; -intialize with constructor CString::CString(LPCSTR)
;; -call SetCString
;; -destruct the temp variable.
;;
mov eax, DWORD PTR _lp$[ebp]
push eax
lea ecx, DWORD PTR $T520[ebp] ; T520 is temp variable
call ??0CString@@QAE@PBD@Z ; CString::CString
push eax
lea ecx, DWORD PTR _foo$[ebp]
call ?SetCString@MyClass@@QAEXABVCString@@@Z ; MyClass::SetCString
lea ecx, DWORD PTR $T520[ebp]
call ??1CString@@QAE@XZ ; CString::~CString
;; Case #4: foo.SetLPCSTR(lp)
;; -call SetLPCSTR (no conversion)
;;
mov eax, DWORD PTR _lp$[ebp]
push eax
lea ecx, DWORD PTR _foo$[ebp]
call ?SetLPCSTR@MyClass@@QAEXPBD@Z ; MyClass::SetLPCSTR
;;================ Get functions ================
;; Case #5: cs = foo.GetCString();
;; -call GetCString
;; -invoke assignment operator top copy CString
;;
lea ecx, DWORD PTR _foo$[ebp]
call ?GetCString@MyClass@@QAEABVCString@@XZ ; MyClass::GetCString
push eax
lea ecx, DWORD PTR _cs$[ebp]
call ??4CString@@QAEHABV0@@Z ; CString::operator=
;; Case #6: cs = foo.GetLPCSTR();
;; -call GetCString
;; -call CString::operator==(LPCSTR)
;;
lea ecx, DWORD PTR _foo$[ebp]
call ?GetLPCSTR@MyClass@@QAEPBDXZ ; MyClass::GetLPCSTR
push eax
lea ecx, DWORD PTR _cs$[ebp]
call ??4CString@@QAEABV0@PBD@Z ; CString::operator=
;; Case #7: lp = foo.GetCString();
;; -call GetCString
;; -convert result to LPCSTR with CString::operator LPCSTR
;;
lea ecx, DWORD PTR _foo$[ebp]
call ?GetCString@MyClass@@QAEABVCString@@XZ ; MyClass::GetCString
mov ecx, eax
call ??BCString@@QBEPBDXZ ; CString::operator char const *
mov DWORD PTR _lp$[ebp], eax
;; Case #8: lp = foo.GetLPCSTR();
;; -call GetLPCSTR (no conversion afterwards)
;;
lea ecx, DWORD PTR _foo$[ebp]
call ?GetLPCSTR@MyClass@@QAEPBDXZ ; MyClass::GetLPCSTR
mov DWORD PTR _lp$[ebp], eax
.
. cleanup, return
.
_main ENDP
Figure 7 Conversion Possibilities for Set Functions
Case | Argument Conversion | MFC Conversion | Inside Set Function |
1 SetCString(cs) | cs ® const CString& | No conversion, just passes a | The code |
pointer to cs. | m_str = cs; | ||
calls | |||
CString::operator=(const | |||
CString&) | |||
which does a quick copy. | |||
Equivalent to | |||
m_str.operator=(cs); | |||
which does | |||
m_str.m_pchData = | |||
cs.m_pchData; | |||
// plus increment ref count | |||
2 SetLPCSTR(cs) | cs ® LPCSTR | Calls inline | The code |
CString::operator LPCSTR | m_str = cs; | ||
to convert cs to LPCSTR. This | calls | ||
just gets cs.m_pchData. | CString::operator=(LPCSTR) | ||
Equivalent to: | to allocate and copy bytes. | ||
SetLPCSTR(cs.m_pchData); | Equivalent to: | ||
m_str.operator(lp); | |||
// allocate, copy | |||
3 SetCString(lp) | lp ® const CString& | Creates a temp variable | The code |
initialized from | m_str = cs; | ||
CString::CString(LPCSTR) | calls | ||
which allocates and copies | CString::operator=(const | ||
bytes. Equivalent to: | CString&) | ||
CString temp(lp); | which does a quick copy. | ||
// allocate, copy | Equivalent to: | ||
SetCString(temp); | m_str.operator=(cs); | ||
temp.CString::~CString(); | which does | ||
This requires calling | m_str.m_pchData = | ||
CString::~CString | cs.m_pchData; | ||
when temp goes out of scope. | // plus increment ref count | ||
The destructor will deallocate | |||
m_pchData if no other CString | |||
is using it. | |||
4 SetLPCSTR(lp) | lp ® LPCSTR | No conversion, just passes | The code |
pointer lp. | m_str = lp; | ||
calls | |||
CString::operator=(LPCSTR) | |||
to allocate and copy bytes. | |||
Equivalent to: | |||
m_str.operator=(lp); | |||
// allocate, copy | |||
cs = Cstring | |||
lp = LPCSTR | |||
red = performance hit |
Figure 8 Conversion Possibilities for Get Functions
Case | Assignment Conversion | MFC Conversion | Inside Get Function |
5 cs=GetCString() | cs ¬ const CString& | Calls | return m_str; |
CString::operator=(const | // as const CString& | ||
CString&) | No conversion, just returns | ||
which does a quick copy. | const pointer to m_str. | ||
Equivalent to: | |||
cs.operator=(GetCString()); | |||
which does | |||
cs.m_pchData = | |||
GetCString().m_pchData; | |||
// and increment ref count | |||
6 cs=GetLPCSTR() | cs ¬ LPCSTR | Calls | return m_str; // as LPCSTR |
CString::operator=(LPCSTR); | Calls | ||
to allocate and copy bytes. | CString::operator LPCSTR | ||
Equivalent to: | (inline) | ||
cs.operator=(GetLPCSTR()); | to convert m_str to LPCSTR. | ||
This just gets cs.m_pchData. | |||
Equivalent to: | |||
return m_str.m_pchData | |||
7 lp=GetCString() | lp ¬ const CString& | Calls inline | return m_str; |
CString::operator LPCSTR | // as const CString& | ||
to get m_pchData. Equivalent to: | No conversion, just returns | ||
lp = GetCString().m_pchData; | const pointer to m_str. | ||
8 lp=GetLPCSTR() | lp ¬ LPCSTR | No conversion. Simple assignment | return m_str; // as LPCSTR |
lp=pointer | Calls | ||
returned. | CSTring::operator LPCSTR | ||
(inline) | |||
to convert m_str to LPCSTR. | |||
This just gets cs.m_pchData. | |||
Equivalent to: | |||
return m_str.m_pchData | |||
cs = Cstring | |||
lp = LPCSTR | |||
red = performance hit |