问题
I have the following code:
std::string F()
{
WideString ws = GetMyWideString();
std::string ret;
StringUtils::ConvertWideStringToUTF8(ws, ret);
return ret;
}
WideString is a third-party class, so are StringUtils. They are a blackbox to me. Second parameter is passed by reference.
When I step through the debugger the line return ret
throws a nasty popup (Visual C++) saying that heap may be corrupted. Upon closer examination copy of the string that gets returned is OK, but the deletion of ret
fails. ret
contains correct value before return.
What could the converting function possibly do to cause this? Any ideas to fix?
Update:
- Project itself is a dll
- StringUtils is a lib
- Project is compiled against Multithreaded CRT (not debug, not dll)
- Program seems to run fine when run outside of Visual Studio
回答1:
- If StringUtils was compiled separately (e.g., with a different compiler version), you may have a conflict in the object layout.
- If StringUtils is in a DLL, you have to ensure that both it and the main program are compiled to use the standard library in a DLL. Otherwise, each module (executable and DLL) will have its own heap. When StringUtils tries to play with data in the string that was allocated from a different heap, bad things happen.
回答2:
The designer of StringUtils designed a very poor API. None of the templated Standard library types should be used in the API's public interface. std::string
is blown out inline. So if the compiler & libraries you are using is not the exact same compiler & libraries used by the implementor of StringUtils, the types can and likely will be different. Fundamentally, the implementor of StringUtils failed to separate the interface from the implementation.
An illustration of the problem. Suppose you are using MSVC 9.0 SP1 and I am using MSVC 8.0. On my compiler, the implementation of std::string might look like this:
class string
{
// : : stuff
private:
int someInt_;
char* someBuf_;
};
...but on your compiler it might look different:
class string
{
// : : stuff
private:
void* impl_;
};
If I write a library function:
void DoSomethingWithAString(std::string& str);
... and you call it, the sizeof(string)
in your code will be different than the sizeof(string)
in my code. The types are NOT the same.
You really only have 2 solutions to your problem:
1) [preferred] Get the implementor of StringUtils to fix his broken code.
2) Replace the library used by your compiler to match the library used by StringUtil's implementor. You might be able to accomplish this by using the same compiler at the same patch level as the implementor used, assuming he didn't replace the implementation of the standard library.
EDIT: 3) A third option would be to stop using StringUtils. Honestly this is probably what I'd do.
回答3:
From what little code you show, I suppose StringUtils::ConvertWideStringToUTF8()
takes a std::string&
as a second parameter. Given that, I don't see how your code can cause a heap corruption.
Note, however, that linking of C++ libraries in general only works when alls the code was compiled using the same compiler and the same compiler settings.
回答4:
Your use of StringUtils
and WideString
makes it look like you're using C++ Builder. Are you trying to mix a C++ Builder module and a Visual C++ module? If so, then you'd definitely see the problems you've described.
You can't pass a Visual C++ std::string
to a C++ Builder function because the C++ Builder code will assume that the parameter uses C++ Builder's std::string
definition. The classes might have different fields, and the fields they have in common might be in a different order.
Even if the classes have the same definitions, the modules will still use different memory managers. The called function will allocate memory for the new string contents using its memory manager, and the caller will use its own memory manager to attempt to free the string's contents later.
来源:https://stackoverflow.com/questions/2343245/can-you-please-explain-this-c-delete-problem