Is it safe to return std::wstring from a DLL?
Asked Answered
V

1

6

According to some older StackOverflow questions ( Unable to pass std::wstring across DLL , C++ DLL returning pointer to std::list<std::wstring> ) it's not considered safe for a C++ DLL to return a std::wstring because there's no guarantee the main program has the same definition of std::wstring and therefore it might cause a crash.

However, in http://en.cppreference.com/w/cpp/string/basic_string , it seems std::wstring can be used interchangeably with a WCHAR array now:

(Since C++11) The elements of a basic_string are stored contiguously, that is, for a basic_string s, &*(s.begin() + n) == &*s.begin() + n for any n in [0, s.size()), or, equivalently, a pointer to s[0] can be passed to functions that expect a pointer to the first element of a CharT[] array.

I've tested this by passing &s[0] to a WINAPI function that expected a WCHAR* buffer and it appeared to work (the std::wstring was correctly populated with the results of the WINAPI). So since std::wstring can apparently be treated like a WCHAR array now, I decided to revisit this question: can a std::wstring be safely returned from a DLL? Why or why not?

Veta answered 17/12, 2013 at 23:44 Comment(0)
C
6

Nothing has changed with regards passing C++ objects across DLL boundaries. That is still not allowed for the same reason as before. The module on the other side of the boundary may have a different definition of the class.

The fact that &s[0] is a valid modifiable pointer to character array is not really relevant. Because a std::basic_string is a lot more than just an array of characters.

Remember that each implementation of std::basic_string can have different internal storage. Can have a different implementation for operator[]. Can be allocated off a different heap. And so on.

I think it is safe to assume that it will never be valid to pass C++ objects across general DLL boundaries. It is only viable if you guarantee that both sides of the boundary are linked against the same runtime instance.

Confectionary answered 17/12, 2013 at 23:47 Comment(9)
I'm confused as to why a std::wstring can be safely passed to a WinAPI but not to a program built with a different C++ compiler. Wouldn't the direct modification of the wstring's character array invalidate whatever other information the wstring implementation has? But for some reason that worked, so it seemed intuitive to me that wstring had gotten more receptive to other forms of modification/assignment.Veta
You don't pass a std::wstring to a Win32 API function. You let a std::wstring supply you with a wchar_t*, into which it is allowed to write. The Win32 API function is indeed modifying the internal character buffer. But a std::wstring is much more than a character buffer.Confectionary
I understand that I'm passing the wstring's character buffer, not the wstring itself, to the WinAPI. But wouldn't the wstring be invalidated when its character buffer is directly modified like that? Hence my assumption that the class had gotten more robust and/or compatible with other classes.Veta
What do you mean by "invalidated"? Remember that std::basic_string has always supplied modifiable references to its character buffer. That's what operator[] does. What you are missing in the comments is that std::basic_string contains more that a character buffer.Confectionary
I always understood the previous problems in passing wstring to a WinAPI function to be because wstring kept track of its internal buffer in some way, and modifying that buffer directly would corrupt the rest of the wstring's information. Was that not the case?Veta
No, that was not the case.Confectionary
@computerfreaker Think of it like this. Suppose that one runtime defines std::basic_string as a class with private members buffer and length. But the other runtime does exactly the same with the members in the opposite order. Neither runtime can understand the other's types. They are simply different types. That is fundamentally what it boils down to. And there are other issues too. Like calling convention potentially being different. Allocation off different heaps. Really, the list of problems is endless!Confectionary
So the length would still be valid after the wstring's buffer was passed to a WinAPI, but this wstring definition would conflict with one where the buffer and length are switched... this explains my question perfectly, thanks!Veta
Probably worth noting that if its an "internal" dll used only by your app, and you build everything with the same compiler, compiler settings, libs etc then it will actually work without any issues.Junta

© 2022 - 2024 — McMap. All rights reserved.