Char* and QString
-
I know this is a generic question as it could easily apply to std::string or other char wrapper, but can someone tell me what a good approach is for following scenario. All I can see is the need to copy strings and have the client be responsible for deleting the copies.
Should I use std::string? I'm reading a lot of articles, api code, stack overflow etc and just can't figure out what a 'good' way of doing this is.
My hesitance in using std::string is mixed messages from what I’ve read about cross boundary compatibility.
I.e main() is a seperate process from the shared library A+B are in.
http://stackoverflow.com/questions/2322095/why-does-this-program-crash-passing-of-stdstring-between-dlls
http://stackoverflow.com/questions/3167560/passing-stdstring-in-a-library-apiThe key here is ease of use for user as well as maximising performance.
Scenario:
I'm implementing an API library.
The external/public functions (free and class members) use char * for all string operations.
Internal/private implementation classes use QString.@
// a.h
Class B;
Class A
{
private:
B* impl;
public:
const char* StringData() const;
}// a.cpp
const char* A::StringData() const
{
QString data = impl->StringData();
xxxxx <- what should I do here for returning a const char * in a safe way
}// b.h
class B
{
QString m_stringData;
public:
const QString StringData() const;
}// b.cpp
const QString B::StringData() const
{
return m_stringData;
}// main.cpp
int main()
{
A a;
const char *stringData = a.StringData(); <- now have a pointer to array that could be deleted anytime, or user has to delete themselves.}
@ -
There is no generic answer for that. As always, it depends. :-)
First of all, can you guarantee that the libraries and the main are always compiled with the same compiler? Or at least with 100% compatible ones? I ask this, because on Windows, each MSVS version has it's on c-runtime which use different heaps. This also happens in service packs:
MSVS2005 != MSVS2005 SP1 != MSVS2008 != MSVS2008 SP1 != MSVS2010
With != means incompatible c-runtime. So if this could happen, you must be memory neutral in the interface (which you might know from older C-APIs and from som Win32 APIs).
There a solution could be:
@
// a.h
Class B;
Class A
{
private:
B* impl;
public:
int StringData(char* pData, int nLength) const;
}// a.cpp
int StringData(char* pData, int nLength) const;
{
QString data = impl->StringData();QByteArray ba = data.toUtf8(); // this depends on the encoding you need int nNeededLength = ba.size() + 1; // I'm not 100% sure whether the endig 0 is part of the byte array... :-( if(0 != pData || nLength >= nNeededLength); { strcpy(pData, ba.constData()); // this depends on the encoding you need } return nNeededLength;
}
// main.cpp
int main()
{
A a;
char* stringData = 0;
int nLength = a.StringData(0,0);
if(0 < nLength)
{
stringData = new char[nLength];
a.StringData(stringData, nLength);
}
// ...
}
@ -
Thanks for quick answer. I figured out part of the ABI issue is differences between implementations and runtimes etc between compilers and versions.
I don't like users having to pass in a buffer, it's ugly and makes coding painful. Standard for C users, not expected by C++ users in a modern library.
Perhaps I need to follow the herd and provide a simple wrapped string class in my API?
I'll always be returning const data so the wrapper should be pretty simple.I've been looking at popular C++ libraries and this seems to be common - I can't see any way around returning copies of strings when crossing module boundaries?