2

I understand why I have C4251 warning when I compile my codes as explained in here. My question is if the accessible export class members are from STL, could we ignore C4251 warning? I give a simple example to illustrate my question:

dll.h

#include <iostream>
#include <string>

using namespace std;

class __declspec(dllexport) HelloWorld
{
public:
  string name;
  HelloWorld();
  HelloWorld(const string &str);

};

dll.cpp

#include "dll.h"

HelloWorld::HelloWorld()
{
  name ="";
}
HelloWorld::HelloWorld(const string &str)
{ 
 name = str;
}

The warning information I have obtained is as followings:

Warning 1   warning C4251: 'HelloWorld::name' : class 'std::basic_string<_Elem,_Traits,_Ax>' needs to have dll-interface to be used by clients of class 'HelloWorld'    *\dll.h 9

My question is: can I ignore this warning? The way how I use this library is also very simple:

#include "dll.h"
#include <iostream>
using namespace std;

int main(void)
{
  HelloWorld myworld;
  myworld.name = "Tom's world";
  cout<<myworld.name<<endl;
  return 0;
}
feelfree
  • 11,175
  • 20
  • 96
  • 167
  • 3
    Just a first point - I wouldn't put the `using namespace std` in your header file. It forces all users of your header to import that namespace into their code. – Roger Rowland May 03 '13 at 15:28
  • 2
    Personally, if the API *is* that simple, I would not use `std::string` at all but stick with `char` etc. for the external interface. – Roger Rowland May 03 '13 at 15:29

2 Answers2

6

You can ignore, but you should understand why this happens and what are the problems you may encounter.

A template is initiated at compile time. This means it may depend on the way you compile your code. The most probable thing that can change code is precompiler define (e.g. #define _NDEBUG or -D_NDEBUG as a command line argument).

If your DLL interface includes object types that depends on things that happen at compile time, all the clients of your DLL must ensure that these types are compiled the same in their code as it is in yours, otherwise errors may occur.

Compiled the same also means using the same compiler. Differences between compilers can also make the code be different between the produced executables and different compilers usually use different STL libraries.

I'll give an example:

template <typename T>
class A
{
    int m_data;
#ifndef NDEBUG
    int m_debugData;
#endif

public:
    void func() 
    {
        m_data =0;
#ifndef NDEBUG
        m_debugData = 0;
#endif
    }
};

In this example, if your DLL is compiled with NDEBUG and the using code is compiled without NDEBUG, calling func() from the user code may cause a runtime error.

selalerer
  • 3,766
  • 2
  • 23
  • 33
  • @selalerer Thanks for your detailed explanations. I wrote a simple program similar to the example you gave, and in need I met with a runtime error. Could you explain why this runtime error will occur? Thanks! – feelfree May 03 '13 at 16:12
  • @feelfree m_debugData = 0 writes to a member that doesn't exist in one DLL. For this DLL it is writing it outside the the object created, in a memory area that doesn't belong to the object. – selalerer May 04 '13 at 08:47
6

To expose implementational details of the Standard C++ Library in your DLL interface, you need some guarantees from the compiler vendor(s) that the way they implemented the Standard C++ library is and will remain compatible with each past and future version of the compiler(s) that you intend to use. Otherwise you risk running into very obscure crashes later on.

This particular vendor is very clear on the extent of these compatibility guarantees:

C4251 can be ignored if you are deriving from a type in the Standard C++ Library, compiling a debug release (/MTd) and where the compiler error message refers to _Container_base.

For more background, you can consult this post.

So the answer is, "no". If it works today, it may break tomorrow.

The situation is analogous to malpractice such as allocating memory in one DLL and freeing it in another DLL.

The immediate risk or corruption is nearly zero if the DLL and all its clients are compiled using the exact same compiler revision and compilation settings, and if you are never mixing debug and release binaries in your work routine. But such dangerous design habits go against the binary reusability of the DLL, and can restrict your future in non-obvious and expensive ways. To continue to feel warned by the compiler is the least thing that you can do against actually crossing the edge.

Community
  • 1
  • 1
Jirka Hanika
  • 13,301
  • 3
  • 46
  • 75