Согласно некоторым более старым вопросам StackOverflow (Невозможно передать std :: wstring через DLL, DLL C ++, возвращающий указатель на std :: list ) для библиотеки C ++ небезопасно возвращать std::wstring, потому что нет гарантии, что основная программа имеет такое же определение std::wstring и, следовательно, может вызвать сбой.

Однако в http://en.cppreference.com/w/cpp/string/basic_string, похоже, теперь std::wstring можно использовать как взаимозаменяемые с массивом WCHAR:

(Начиная с C ++ 11) Элементы basic_string хранятся непрерывно, то есть для basic_string s, & * (s.begin () + n) == & * s.begin () + n для любого n в [0, s.size ()) или, что то же самое, указатель на s [0] может быть передан функциям, которые ожидают указатель на первый элемент массива CharT [].

Я проверил это, передав &s[0] функции WINAPI, которая ожидала буфер WCHAR*, и, похоже, она работала (std::wstring был правильно заполнен результатами WINAPI). Итак, поскольку теперь std::wstring можно рассматривать как массив WCHAR, я решил вернуться к этому вопросу: можно ли безопасно вернуть std::wstring из DLL? Почему или почему нет?

5
cf stands with Monica 18 Дек 2013 в 03:44

1 ответ

Лучший ответ

Ничего не изменилось в отношении передачи объектов C ++ через границы DLL. Это по-прежнему запрещено по той же причине, что и раньше. Модуль по другую сторону границы может иметь другое определение класса.

Тот факт, что &s[0] является допустимым изменяемым указателем на массив символов, на самом деле не имеет значения. Потому что std::basic_string - это намного больше, чем просто массив символов.

Помните, что каждая реализация std::basic_string может иметь разную внутреннюю память. Может иметь другую реализацию для operator[]. Может быть выделен из другой кучи. И так далее.

Я думаю, можно с уверенностью предположить, что передача объектов C ++ через общие границы DLL никогда не будет допустимой. Это возможно только в том случае, если вы гарантируете, что обе стороны границы связаны с одним и тем же экземпляром среды выполнения.

6
David Heffernan 18 Дек 2013 в 03:47
Я не понимаю, почему std::wstring можно безопасно передать в WinAPI, но не в программу, созданную с помощью другого компилятора C ++. Разве прямая модификация символьного массива wstring не сделает недействительной любую другую информацию, имеющуюся в реализации wstring? Но по какой-то причине это сработало, поэтому мне показалось интуитивно понятным, что wstring стал более восприимчивым к другим формам модификации / назначения.
 – 
cf stands with Monica
18 Дек 2013 в 04:06
Вы не передаете std::wstring функции Win32 API. Вы позволяете std::wstring снабжать вас wchar_t*, в который разрешено писать. Функция Win32 API действительно изменяет внутренний символьный буфер. Но std::wstring - это гораздо больше, чем символьный буфер.
 – 
David Heffernan
18 Дек 2013 в 04:07
Я понимаю, что я передаю WinAPI символьный буфер wstring, а не сам wstring. Но не станет ли wstring недействительным, если его символьный буфер напрямую изменен таким образом? Отсюда мое предположение, что класс стал более надежным и / или совместимым с другими классами.
 – 
cf stands with Monica
18 Дек 2013 в 04:13
1
Подумайте об этом так. Предположим, что одна среда выполнения определяет std::basic_string как класс с закрытыми членами buffer и length. Но другая среда выполнения делает то же самое с членами в обратном порядке. Ни одна среда выполнения не может понять типы другой. Они просто разные типы. По сути, это то, к чему все сводится. Есть и другие проблемы. Как соглашение о вызовах, которое потенциально может отличаться. Выделение из разных куч. Действительно, список проблем бесконечен!
 – 
David Heffernan
18 Дек 2013 в 04:29
1
Вероятно, стоит отметить, что если это «внутренняя» dll, используемая только вашим приложением, и вы создаете все с одним и тем же компилятором, настройками компилятора, библиотеками и т. Д., Тогда она действительно будет работать без каких-либо проблем.
 – 
paulm
5 Сен 2014 в 23:23