简体   繁体   English

您能解释一下C ++删除问题吗?

[英]Can you please explain this C++ delete problem?

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. WideString是第三方类,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. 当我逐步通过调试器时,行return ret会抛出一个讨厌的弹出窗口(Visual C ++),提示堆可能已损坏。 Upon closer examination copy of the string that gets returned is OK, but the deletion of ret fails. 经过仔细检查,返回的字符串的副本可以,但是删除ret失败。 ret contains correct value before return. ret在返回之前包含正确的值。

What could the converting function possibly do to cause this? 转换功能可能会导致什么? Any ideas to fix? 有什么想法要解决吗?

Update: 更新:

  • Project itself is a dll 项目本身是一个dll
  • StringUtils is a lib StringUtils是一个lib
  • Project is compiled against Multithreaded CRT (not debug, not dll) 项目是针对多线程CRT编译的(不是调试,不是dll)
  • Program seems to run fine when run outside of Visual Studio 在Visual Studio外部运行时,程序似乎运行良好
  1. If StringUtils was compiled separately (eg, with a different compiler version), you may have a conflict in the object layout. 如果StringUtils是单独编译的(例如,使用不同的编译器版本),则对象布局可能会发生冲突。
  2. 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. 如果StringUtils位于DLL中,则必须确保将它和主程序都编译为使用DLL中的标准库。 Otherwise, each module (executable and DLL) will have its own heap. 否则,每个模块(可执行文件和DLL)都会有自己的堆。 When StringUtils tries to play with data in the string that was allocated from a different heap, bad things happen. 当StringUtils尝试处理从其他堆分配的字符串中的数据时,会发生不良情况。

The designer of StringUtils designed a very poor API. StringUtils的设计者设计了一个非常差的API。 None of the templated Standard library types should be used in the API's public interface. API的公共接口中不应使用任何模板化的标准库类型。 std::string is blown out inline. std::string被内联吹出。 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. 因此,如果您使用的编译器和库与StringUtils的实现者使用的编译器和库不完全相同,则类型可能并且可能会有所不同。 Fundamentally, the implementor of StringUtils failed to separate the interface from the implementation . 从根本上讲,StringUtils的实现者未能将接口与实现分开

An illustration of the problem. 问题的例证。 Suppose you are using MSVC 9.0 SP1 and I am using MSVC 8.0. 假设您使用的是MSVC 9.0 SP1,而我使用的是MSVC 8.0。 On my compiler, the implementation of std::string might look like this: 在我的编译器上,std :: string的实现可能如下所示:

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. ...你称呼它, sizeof(string)在你的代码会比不同sizeof(string)在我的代码。 The types are NOT the same. 类型不同。

You really only have 2 solutions to your problem: 您实际上只有2种解决方案:

1) [preferred] Get the implementor of StringUtils to fix his broken code. 1)[首选]获取StringUtils的实现者来修复其损坏的代码。

2) Replace the library used by your compiler to match the library used by StringUtil's implementor. 2)替换编译器使用的库,以匹配StringUtil的实现者使用的库。 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. 编辑:3)第三种选择是停止使用StringUtils。 Honestly this is probably what I'd do. 老实说,这可能就是我要做的。

From what little code you show, I suppose StringUtils::ConvertWideStringToUTF8() takes a std::string& as a second parameter. 从您显示的代码中,我想StringUtils::ConvertWideStringToUTF8()std::string&作为第二个参数。 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. 但是请注意,通常只有在使用相同的编译器和相同的编译器设置来编译所有代码时,C ++库的链接才有效。

Your use of StringUtils and WideString makes it look like you're using C++ Builder. 您对StringUtilsWideString使其看起来像您在使用C ++ Builder。 Are you trying to mix a C++ Builder module and a Visual C++ module? 您是否要混合使用C ++ Builder模块和Visual C ++模块? 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. 您不能将Visual C ++ std::string传递给C ++ Builder函数,因为C ++ Builder代码将假定该参数使用C ++ Builder的std::string定义。 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. 被调用函数将使用其内存管理器为新的字符串内容分配内存,而调用方将使用其自己的内存管理器来稍后尝试释放字符串的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM