2

我有以下代码:

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 是一个库
  • 项目是针对多线程 CRT 编译的(不是调试,不是 dll)
  • 在 Visual Studio 之外运行时,程序似乎运行良好
4

4 回答 4

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

StringUtils 的设计者设计了一个非常糟糕的 API。API 的公共接口中不应使用任何模板化的标准库类型。 std::string被吹出内联。因此,如果您使用的编译器和库与 StringUtils 的实现者使用的编译器和库不完全相同,则类型可能并且很可能会有所不同。从根本上说,StringUtils 的实现者未能将接口与实现分开

问题的说明。假设您使用的是 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) [preferred] 获取 StringUtils 的实现者来修复他损坏的代码。

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

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

于 2010-02-26T17:06:34.343 回答
1

从您显示的小代码中,我想StringUtils::ConvertWideStringToUTF8()将 astd::string&作为第二个参数。鉴于此,我看不出您的代码如何导致堆损坏。

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

于 2010-02-26T16:55:10.820 回答
0

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

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

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

于 2010-02-26T18:03:58.947 回答