2

次のコードがあります。

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

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

WideString はサードパーティ クラスであり、StringUtils も同様です。彼らは私にとってブラックボックスです。2 番目のパラメーターは参照によって渡されます。

デバッガーをステップ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を使用していて、MSVC8.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)3番目のオプションは、StringUtilsの使用を停止することです。正直なところ、これはおそらく私がすることです。

于 2010-02-26T17:06:34.343 に答える
1

あなたが示す小さなコードから、私は2番目のパラメータとしてをStringUtils::ConvertWideStringToUTF8()とると思います。std::string&それを考えると、あなたのコードがどのようにヒープの破損を引き起こす可能性があるのか​​わかりません。

ただし、一般にC ++ライブラリのリンクは、すべてのコードが同じコンパイラと同じコンパイラ設定を使用してコンパイルされた場合にのみ機能することに注意してください。

于 2010-02-26T16:55:10.820 に答える
0

StringUtilsとを使用すると、 WideStringC++ Builder を使用しているように見えます。C++ Builder モジュールと Visual C++ モジュールを混在させようとしていますか? もしそうなら、あなたは間違いなくあなたが説明した問題を見るでしょう.

Visual C++ を C++ Builder 関数に渡すことはできませんstd::string。これは、C++ Builder コードが、パラメーターが C++ Builder のstd::string定義を使用していると想定するためです。クラスは異なるフィールドを持つ場合があり、共通するフィールドの順序が異なる場合があります。

クラスの定義が同じであっても、モジュールは異なるメモリ マネージャーを使用します。呼び出された関数は、メモリ マネージャーを使用して新しい文字列の内容にメモリを割り当て、呼び出し元は独自のメモリ マネージャーを使用して、後で文字列の内容を解放しようとします。

于 2010-02-26T18:03:58.947 に答える