Можете ли вы объяснить эту проблему удаления C ++? - PullRequest
2 голосов
/ 26 февраля 2010

У меня есть следующий код:

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 голосов
/ 26 февраля 2010
  1. Если StringUtils был скомпилирован отдельно (например, с другой версией компилятора), у вас может возникнуть конфликт в макете объекта.
  2. Если StringUtils находится в DLL, вы должны убедиться, что и она, и основная программа скомпилированы для использования стандартной библиотеки в DLL. В противном случае каждый модуль (исполняемый и DLL) будет иметь свою собственную кучу. Когда StringUtils пытается воспроизвести данные в строке, выделенной из другой кучи, происходят плохие вещи.
2 голосов
/ 26 февраля 2010

Разработчик 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) [предпочтительно] Получить разработчик StringUtils, чтобы исправить его испорченный код.

2) Замените библиотеку, используемую вашим компилятором, на библиотеку, используемую разработчиком StringUtil. Вы могли бы достичь этого, используя тот же компилятор на том же уровне исправлений, что и используемый разработчик, при условии, что он не заменил реализацию стандартной библиотеки.

РЕДАКТИРОВАТЬ: 3) Третий вариант будет прекратить использование StringUtils. Честно говоря, это, вероятно, то, что я бы сделал.

1 голос
/ 26 февраля 2010

Из того небольшого кода, который вы показываете, я полагаю, StringUtils::ConvertWideStringToUTF8() принимает std::string& в качестве второго параметра. Учитывая это, я не понимаю, как ваш код может вызвать повреждение кучи.

Обратите внимание, однако, что связывание библиотек C ++ в целом работает только тогда, когда весь код был скомпилирован с использованием одного и того же компилятора и одинаковых настроек компилятора.

0 голосов
/ 26 февраля 2010

При использовании StringUtils и WideString создается впечатление, что вы используете C ++ Builder. Вы пытаетесь смешать модуль C ++ Builder и модуль Visual C ++? Если это так, то вы наверняка увидите описанные проблемы.

Нельзя передать Visual C ++ std::string в функцию C ++ Builder, поскольку код C ++ Builder предполагает, что параметр использует определение std::string C ++ Builder. Классы могут иметь разные поля, а общие поля могут быть в другом порядке.

Даже если классы имеют одинаковые определения, модули все равно будут использовать разные менеджеры памяти. Вызываемая функция будет выделять память для нового содержимого строки, используя свой менеджер памяти, а вызывающая сторона будет использовать свой собственный менеджер памяти, чтобы позже попытаться освободить содержимое строки.

...