Link to home
Start Free TrialLog in
Avatar of Rumil
Rumil

asked on

Implicit conversion problem

I declare a function which takes a CString, and then pass a JString to it.  A typecast is necessary, so I create JString::operator CString () const, which builds and returns a CString that copies the JString.

Implicit conversion is done, and my function runs correctly, but on exiting, a memory library de-allocation error results.  If I _explicitly_ convert the JString parameter to a CString with a simple (CString) typecast, there's no problem!  Why does MSVC 1.52 produce different object code for these possibilities, and how can I fix the implicit conversion to work correctly?

(Or better still, is there a simple C++ string class available that is more efficient than the MFC CString class, and can return references to strings rather than creating gratuitous copies whenever you return string values, like Java's string class?)
ASKER CERTIFIED SOLUTION
Avatar of yonat
yonat

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nietod
nietod

I beleive that MFC's string class is well written and it works well with MFC.  (MFC procedures may take it as a parameters, so using a different type of string is inconvenient and may require lots of conversions, and since conversions are the problem...)

In any case, regardless of the string used, this problem should not happen.

The common problems I've seen in this area are: procedures that allocate memory that does not get disposed or procedures that return pointers to local variables or return structures that use pointers to local variables. Can you post the code of your conversion and any other necessary code?
The advantage of using the standard string class is that it is, well, standard. The advantage of using CString is that MFC uses it. So if you want your code to be portable, you should use the standard string. If your code is closely bound to MFC, use CString.
I was under the impression (maybe mistakenly as I re-read the question) that Rumil is using MFC, and thus felt that MFC's strings make sense.  In any case, the problem may not be in the string he chooses, but in the code that uses the string.
Avatar of Rumil

ASKER

Problem: Where do I find good documentation for the standard string class?  It would take me a very long time to determine whether the class is adequate for my needs by reading the source code.  Even MFC is more legible.

MFC's CStrings are inadequate for my needs because it's not safe under Visual C++ 1.52 to return a reference to a CString.  Whenever I have a chain of functions that each pass a CString back to the last one, my program must return the CString "by value," wasting a lot of time copying memory.  Also, I've had some memory-allocation problems; code like <string = "Longer string", string = "Short"> will always leave the extra bytes allocated, and I know no way to free the space without deleting the whole string.

My code uses MFC, but not heavily enough to require frequent conversion if I thoroughly replace the CString class with JString in my own code.  However, I'm trying to replace CStrings with JStrings in just a few places at a time.  This strategy makes it easier to track down strange memory allocation errors like this one.


Here's the pertinent code:
void AFunction () {
  JString word = "Arbitrary";
  if (Find (word2) != NotFound)...
  }

int Find (CString s)    {  return Doc->Find (s);  }

int CMyDoc::Find (const CString& s) const
  {   ...  }

func CString JString::operator CString () const
  {
  CString retValue;
  for (int loop1 = 0;  loop1 < MSize;  loop1++)
    retValue += MData [loop1];
  return retValue;
  }


This code doesn't work.  But if I rewrite the first line as:
if (Find ((CString) word2) != NotFound)...
there are no problems!

I'm working around this specific problem simply by replacing the operator= with a ConvertToCString function, to force explicit conversion.  But I want to know what's going on to make sure I don't run into other, similar problems as I replace the CString class with my JString class.  Is it indeed just a bizarre Microsoft bug?
Hmm, doesn't sound like the standard string can solve your problems - your conversion operator is not being called implicitly. If this is a compiler bug, it is specific to 1.52 - I haven't seen it in 4.x and 5.0.

I might see your problem, or just a typo.

the line

func CString JString::operator CString () const

should be just

JString::operator CString () const

you do not declare a return value ("CString") for a conversion operator and I have no idea what the "func" bit was.
nietod is right. You should reject my answer, and ask him to submit one.
Does removing that stuff make the conversion work?
Avatar of Rumil

ASKER

I've defined "func" to mean "inline" in my header files, and nothing at all in my source files, allowing me to conveniently move functions in and out of headers in a multi-module program as their complexity changes.  Nothing there.

Unfortunately, removing the "CString" return type didn't change anything either.  The problem is indeed compiler-related; MSVC produces different object code for the function-call depending on whether the typecast is done explicitly or implicitly.  (And yes, I tried deleting the conversion function long ago, just to make sure there were no other implicit conversions available.)

Under the assumption that this is just an obscure MSVC bug, I've replaced my operator CString function with a ConvertToCString function.  I've converted many instances of CStrings in my library to JStrings and CStringImages and haven't discovered any memory leaks yet.  I'm still nervous, though.
What is the difference in the code in the two cases?  That may reveal something.

Also I had missed one of your comments up there mentions a couple  of interesting things.  

You talk about returning strings as references to eliminate copying time.  As you might know, but in case you don't, that cannot be done unless the string is passed to the procedure in some way.  i.e. a conversion procedure cannot create a new (local) string and return a reference to it.  That will result in  problems.  The STL's string class, and I believe (or I would hope) the MFC string class uses reference counted string buffers.  This means that passing/returning strings by value does not involve copying the string and is very fast and efficient.  There is no need to pass/return strings by reference except where you actually need the reference.