你能解释一下这个C ++删除问题吗?

时间:2010-02-26 16:51:20

标签: c++ corruption heap-memory one-definition-rule

我有以下代码:

std::string F()
{
  WideString ws = GetMyWideString();

  std::string ret;
  StringUtils::ConvertWideStringToUTF8(ws, ret);
  return ret;
}

WideString是第三方类,StringUtils也是如此。他们对我来说是个黑盒子。第二个参数通过引用传递。

当我单步执行调试器时,行return ret会抛出一个讨厌的弹出窗口(Visual C ++),说堆可能已损坏。仔细检查后,返回的字符串副本是正常的,但删除ret失败。 ret在返回之前包含正确的值。

转换功能可能会导致什么?有什么想法要修复吗?

更新

  • 项目本身就是一个dll
  • StringUtils是一个lib
  • 项目是针对多线程CRT(不是调试,而不是dll)
  • 编译的
  • 程序似乎在Visual Studio
  • 之外运行时运行正常

4 个答案:

答案 0 :(得分:4)

  1. 如果StringUtils是单独编译的(例如,使用不同的编译器版本),则可能在对象布局中存在冲突。
  2. 如果StringUtils在DLL中,则必须确保它和主程序都被编译为使用DLL中的标准库。否则,每个模块(可执行文件和DLL)都有自己的堆。当StringUtils尝试使用从不同堆分配的字符串中的数据时,会发生不好的事情。

答案 1 :(得分:2)

StringUtils的设计者设计了一个非常糟糕的API。 API的公共接口中不应使用任何模板化的标准库类型。内联std::string被炸毁了。所以如果编译器&您正在使用的库不是完全相同的编译器和放大器。 StringUtils的实现者使用的库,类型可以并且可能会有所不同。从根本上说,StringUtils failed to separate the interface from the implementation的实现者。

问题的说明。假设您使用的是MSVC 9.0 SP1,我使用的是MSVC 8.0。在我的编译器上,std :: string的实现可能如下所示:

class string
{
// : :  stuff
private:
  int someInt_;
  char* someBuf_;
};

...但是在您的编译器上它可能看起来不同:

class string
{
// : :  stuff
private: 

  void* impl_;
};

如果我写一个库函数:

void DoSomethingWithAString(std::string& str);

...您调用它,代码中的sizeof(string)将与我代码中的sizeof(string)不同。类型不一样。

你真的只有2个问题的解决方案:

1)[首选]获取StringUtils的实现者来修复他破碎的代码。

2)替换编译器使用的库以匹配StringUtil的实现者使用的库。您可以通过在与使用的实现者相同的补丁级别使用相同的编译器来实现此目的,假设他没有替换标准库的实现。

编辑:3)第三种选择是停止使用StringUtils。老实说这可能就是我要做的。

答案 2 :(得分:1)

从您显示的小代码中,我认为StringUtils::ConvertWideStringToUTF8()std::string&作为第二个参数。鉴于此,我没有看到您的代码如何导致堆损坏。

但是,请注意,通常只有在使用相同的编译器和相同的编译器设置编译所有代码时,C ++库的链接才有效。

答案 3 :(得分:0)

您使用StringUtilsWideString会让您看起来像是在使用C ++ Builder。您是否尝试混合使用C ++ Builder模块和Visual C ++模块?如果是这样,那么你肯定会看到你所描述的问题。

您无法将Visual C ++ std::string传递给C ++ Builder函数,因为C ++ Builder代码将假定该参数使用C ++ Builder的std::string定义。这些类可能有不同的字段,它们共有的字段可能有不同的顺序。

即使类具有相同的定义,模块仍将使用不同的内存管理器。被调用的函数将使用其内存管理器为新的字符串内容分配内存,调用者将使用自己的内存管理器来尝试稍后释放字符串的内容。