bsruth
bsruth

Reputation: 5502

Is this a valid way to provide STL functions in a library regardless of CRT version?

I am trying to migrate some static C++ libraries into DLLs with a C interface so I don't need to build a separate version of the library for every version of Visual Studio (i.e. CRT) we want to support. However, I do like the convenience of using STL objects for some of the function calls. I came up with something that seems to work, but was wondering if there may be some hidden things that I'm just not thinking of.

Here is what I came up with to get STL versions of functions while still maintaining Visual Studio independence.

Original library function:

//library.h
...
std::wstring GetSomeString();
...
StringGenerator* mStrGen; //assume forward declared for pimpl implementation

//library.cpp
std::wstring library::GetSomeString()
{
  return mStrGen->GetString(); //returns a wstring;
}

First, I created a private function that would provide the C interface

//library.h
__declspec(dllexport) void GetSomeStringInternal(wchar_t* pSomeString);

//library.cpp
void library::GetSomeString(wchar_t*& pSomeString)
{
    if(pSomeString!= nullptr) {
        delete [] pSomeString; //assumes allocated by the DLL
    }

    std::wstring tmpString(mStrGen->GetString());

    size_t stringLength(tmpString.size());

    stringToReturn = new wchar_t[stringLength + 1];

    wcscpy_s(pSomeString, stringLength + 1, tmpString.c_str());
}

Next, I added a private function that deallocates memory allocated by the DLL

//library.h
__declspec(dllexport) void FreeArray(void* arrayPtr);

//library.cpp
void library::FreeArray(void* arrayPtr)
{
 if(arrayPtr) {
   delete [] arrayPtr; 
  }
}

Finally, I converted the original C++ function returning a string into a function that calls the internal C interface function

//library.h

std::wstring GetSomeString()
{
  std::wstring someString(L"");
  wchar_t* pSomeString= NULL;

  GetSomeStringInternal(pSomeString);
  someString = pSomeString;

  FreeArray(pSomeString);
  return someString;
}

//library.cpp
//removed GetSomeString from cpp since it is defined in header

My thinking is that since the header will be compiled every time it is included, an application that uses a different version of the CRT will compile the function using its implementation of the CRT. All data passed into and out of the library uses a C interface to preserve compatibility and memory is allocated and freed by the library so you don't run into one version of the CRT trying to free memory from a different version.

It seems to perform as I intend:

Is there anything I am missing, or is this a valid way of going about providing a C++ interface to a library that is Visual Studio version independent?

Side note: I have run into some deletion issues if I have a program that uses a std::shared_ptr<library>, but haven't researched that issue enough and will probably have a follow up question on that problem.

Upvotes: 1

Views: 225

Answers (1)

Nathan Monteleone
Nathan Monteleone

Reputation: 5470

One thing I could see becoming a problem is if you actually needed to pass large objects around by reference for performance reasons. You're dealing with the binary compatibility issues by copying all the data to and from a compatible format, which is fine until it becomes a performance issue.

Upvotes: 2

Related Questions