Почему я получаю повреждение кучи при изменении размера вектора внутри DLL? - PullRequest
1 голос
/ 20 июня 2019

Я пишу XLL (используя библиотеку XLW), которая вызывает функцию DLL. Эта функция DLL получает ссылку на вектор, изменяет вектор и возвращает его по аргументу.

У меня есть решение VS10 с несколькими проектами c ++, некоторыми DLL и XLL, которые будут вызывать функции DLL из Excel. Я скомпилировал все, используя компилятор VS10, с _HAS_ITERATOR_DEBUGGING=0 и _CRT_SECURE_NO_WARNINGS и использовал одну и ту же библиотеку времени выполнения (/ MDd) для всех проектов.

Мне также пришлось перестроить библиотеку XLW в соответствии с _HAS_ITERATOR_DEBUGGING=0, которую я должен использовать в своих проектах.

При вызове xll_function я получал ошибки Heap Corruption и не мог понять, почему. После того, как я попытался изменить свой вектор перед вызовом функции dll, ошибка пошла. То есть я могу вызвать функцию и получить верный вектор, возвращаемый аргументом, и без искажений кучи.

Может ли кто-нибудь пролить свет на это? Поскольку я новичок в использовании DLL, я не уверен, что это должно произойти, или я делаю что-то не так.

Как вы можете видеть из приведенного ниже кода, функция dll попытается изменить размер forwards, и я думаю, что именно в этом и заключается ошибка кучи. Я пытаюсь понять, почему это происходит и как это изменение размера и распределения работает для DLL. Возможно, я не могу изменить размер вектора, выделенного в другой куче.

** Код ниже - первая функция является статическим методом в классе из проекта dll, а вторая функция экспортируется в XLL.

void dll_function(double quote, const std::vector<double>& drift, const std::vector<double>& divs, std::vector<double>& forwards)
{
    size_t size = drift.size();
    forwards.resize(size);

    for( size_t t = 0; t < size; t++)
    {
        forwards[t] = (quote - divs[t]) * drift[t];
    }
}


MyArray xll_function(double quote, const MyArray& drift, const MyArray& divs)
{
    // Resizing the vector before passing to function
    std::vector<double> forwards(drift.size());

    dll_function(quote, drift, divs, forwards);

    return forwards;
}

1 Ответ

5 голосов
/ 20 июня 2019

Чтобы передать ссылки на std :: vector или другие коллекции C ++ через границы DLL, необходимо выполнить следующие действия:

  1. Использовать один и тот же компилятор C ++ для обоих модулей и одну и ту же версиюкомпилятор.

  2. В настройках проекта задайте то же значение, что и для настройки General / Platform Toolset.

  3. В настройках проекта настройте C /Значение C ++ / Generation Code / Runtime Library для «Многопоточная DLL (/ MD)» или Многопоточная отладочная DLL (/ MDd) для конфигурации отладки.Если у одного из проектов есть зависимость, которая требует статической настройки CRT, извините, вам не повезло, это не сработает.

  4. Используйте одинаковую конфигурацию с обеих сторон: если вы 'Мы создали отладочную версию библиотеки DLL, не связывайтесь с версией выпуска потребляющего EXE-файла.Также не изменяйте определения препроцессора, такие как _ITERATOR_DEBUG_LEVEL или _SCL_SECURE_NO_WARNINGS, или, если вы это сделали, измените их на одно и то же значение для обоих проектов.

Причина этих осложнений в C ++ отсутствует.стандартизированный ABI.Расположение памяти в std :: vector и других классах меняется в зависимости от многих вещей.Операторы new и delete также находятся в стандартной библиотеке C ++, т. Е. Вы не можете выделить память с C ++ в одном модуле, бесплатно в другом.

Если вы не можете выполнить эти условия, то 'Вот несколько обходных путей, вот хорошее резюме: https://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

...