The following piece of code usually triggers warning C4251:
'MyClass::m_object' : class 'ThirdPartyTemplate<T>' needs to have
dll-interface to be used by clients of class 'MyClass':

template <typename T>
class ThirdPartyTemplate
{
public:
// Constructor.
ThirdPartyTemplate() {}
};

class __declspec(dllexport) MyClass
{
ThirdPartyTemplate<int> m_object; // warning C4251!
};

Is there really anything wrong about it? Here at LKEB (www.lkeb.nl), we
often get this kind of warning, when using Boost or STL. Now it appears
that one can get rid of the warning, by wrapping the ThirdPartyTemplate<int>
object inside a simple struct:

struct WrapperStruct
{
ThirdPartyTemplate<int> wrappedObject;
};

class __declspec(dllexport) MyClassWithoutWarning
{
WrapperStruct m_wrapper; // No warning! :-)
};

Does this approach really solve the problem, or does it only hide the
message?


Kind regards,
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center

Re: A solution to warning C4251 - class needs to have dll-interface...? by Doug

Doug
Tue Oct 16 11:59:31 PDT 2007

On Tue, 16 Oct 2007 20:37:14 +0200, "Niels Dekker - no return address"
<unknown@this.is.invalid> wrote:

>The following piece of code usually triggers warning C4251:
>'MyClass::m_object' : class 'ThirdPartyTemplate<T>' needs to have
>dll-interface to be used by clients of class 'MyClass':
>
> template <typename T>
> class ThirdPartyTemplate
> {
> public:
> // Constructor.
> ThirdPartyTemplate() {}
> };
>
> class __declspec(dllexport) MyClass
> {
> ThirdPartyTemplate<int> m_object; // warning C4251!
> };
>
>Is there really anything wrong about it?

It's nothing #pragma warning(disable) can't cure. :)

>Here at LKEB (www.lkeb.nl), we
>often get this kind of warning, when using Boost or STL. Now it appears
>that one can get rid of the warning, by wrapping the ThirdPartyTemplate<int>
>object inside a simple struct:
>
> struct WrapperStruct
> {
> ThirdPartyTemplate<int> wrappedObject;
> };
>
> class __declspec(dllexport) MyClassWithoutWarning
> {
> WrapperStruct m_wrapper; // No warning! :-)
> };
>
>Does this approach really solve the problem, or does it only hide the
>message?

It merely hides it. Think about the motivation for this warning. It's
emitted when you use a non-dllexported class X in a dllexported class Y.
What's so bad about that? Well, suppose Y has an inline function y_f that
calls a function x_f belonging to X that is not also inline. If y_f is
inlined inside some client that doesn't statically link X, the link will
fail, because x_f won't be found. Concerning your code, ThirdPartyTemplate
is a class template, and template code is generated wherever it's needed,
so this is not an issue. You may end up with some code bloat due to
duplicated template instantiations, but you can usually ignore this. There
are two workarounds (and I use that term lightly):

1. You can explicitly instantiate and dllexport the specializations you use
from some DLL, or more generally,

2. You can define a wrapper class that has no inline functions and defines
all the potentially compiler-generated functions (default ctor, copy ctor,
dtor, and assignment operator) and dllexport that.

It looks like you're sort of on your way to (2) with MyClass.

--
Doug Harrison
Visual C++ MVP

Re: A solution to warning C4251 - class needs to have dll-interface...? by Niels

Niels
Wed Oct 17 10:22:37 PDT 2007

Thank you, Doug! Your answer is very helpful to me :-)

Doug Harrison [MVP] wrote:
> [...] Think about the motivation for this warning. It's
> emitted when you use a non-dllexported class X in a dllexported class
> Y. What's so bad about that? Well, suppose Y has an inline function
> y_f that calls a function x_f belonging to X that is not also inline.
> If y_f is inlined inside some client that doesn't statically link X,
> the link will fail, because x_f won't be found.

It sounds like this scenario won't happen when using an STL container within
my dllexported class, right? Because the functions of the STL containers
are completely defined by their header files. We're using both VC++ 7.1 and
8.0, with the included STL.

Anyway, you're just talking about link errors, right? I was afraid that the
warning indicated that my program might have runtime crashes! Especially
because of Q172396, "You may experience an access violation when you access
an STL object through a pointer or reference in a different DLL or EXE".
http://support.microsoft.com/kb/q172396/

Q172396 says: "Most classes in the Standard C++ Libraries use static data
members..." Apparently this is the cause of those access violations. So
you should never return a reference to an STL container from an dllexported
class, right? Is it even unsafe to return a reference to an std::string,
or a reference to a vector?

Kind regards,

Niels



Re: A solution to warning C4251 - class needs to have dll-interface...? by Doug

Doug
Wed Oct 17 13:24:00 PDT 2007

On Wed, 17 Oct 2007 19:22:37 +0200, "Niels Dekker - no return address"
<unknown@this.is.invalid> wrote:

>It sounds like this scenario won't happen when using an STL container within
>my dllexported class, right? Because the functions of the STL containers
>are completely defined by their header files. We're using both VC++ 7.1 and
>8.0, with the included STL.

I think you should be OK, but there are some important restrictions which I
talk about below.

>Anyway, you're just talking about link errors, right? I was afraid that the
>warning indicated that my program might have runtime crashes! Especially
>because of Q172396, "You may experience an access violation when you access
>an STL object through a pointer or reference in a different DLL or EXE".
>http://support.microsoft.com/kb/q172396/
>
>Q172396 says: "Most classes in the Standard C++ Libraries use static data
>members..." Apparently this is the cause of those access violations.

Yes, and it's a tangential issue. The problem is that each module will get
its own instance of the static data, instead of there being one instance of
the static data for the entire program. The standard workaround for that is
to explicitly instantiate and dllexport all the specializations you're
going to use.

>So you should never return a reference to an STL container from an dllexported
>class, right? Is it even unsafe to return a reference to an std::string,
>or a reference to a vector?

That should be fine, and the static data usage by the classes Q172396 is
talking about was eliminated in VC7. (Dinkumware also published patches for
the associative containers for VC6.)

Note that sharing C++ objects in this way between modules must be
considered equivalent to static linking for compilation dependency
purposes. In particular, all the modules should be compiled with the same
options, and they must all use the same CRT DLL. It is very important to
understand this, because otherwise, each module will end up with its own
CRT state, including heap, file descriptors, and so forth, and you won't be
able to fully share C++ objects between modules. For example, if modules X
and Y use different CRTs, you won't be able to delete an object in one that
was created by the other.

--
Doug Harrison
Visual C++ MVP

Re: A solution to warning C4251 - class needs to have dll-interface...? by Ben

Ben
Thu Oct 18 07:44:17 PDT 2007


"Doug Harrison [MVP]" <dsh@mvps.org> wrote in message
news:i4rch35fuvcdpl8jn7skubsf3v7rl8qph8@4ax.com...
> On Wed, 17 Oct 2007 19:22:37 +0200, "Niels Dekker - no return address"
> <unknown@this.is.invalid> wrote:
>
>>It sounds like this scenario won't happen when using an STL container
>>within
>>my dllexported class, right? Because the functions of the STL containers
>>are completely defined by their header files. We're using both VC++ 7.1
>>and
>>8.0, with the included STL.

[snip]

> Note that sharing C++ objects in this way between modules must be
> considered equivalent to static linking for compilation dependency
> purposes. In particular, all the modules should be compiled with the same
> options, and they must all use the same CRT DLL. It is very important to
> understand this, because otherwise, each module will end up with its own
> CRT state, including heap, file descriptors, and so forth, and you won't
> be
> able to fully share C++ objects between modules. For example, if modules X
> and Y use different CRTs, you won't be able to delete an object in one
> that
> was created by the other.

The poster is using different CRT (different VC++ versions). Moreover, it's
different STL headers as well, so there will be ODR violations and therefore
runtime failures.

>
> --
> Doug Harrison
> Visual C++ MVP



Re: A solution to warning C4251 - class needs to have dll-interface...? by Niels

Niels
Thu Oct 18 09:52:35 PDT 2007

Ben Voigt [C++ MVP] wrote:
> The poster is using different CRT (different VC++ versions). Moreover,
> it's different STL headers as well, so there will be
> ODR violations and therefore runtime failures.

Sorry for being unclear. My question was not about mixing different VC++
versions. Here at LKEB, we're using both VC++ 7.1 and 8.0, but usually not
at the same time! I wasn't intending to mix different versions of the STL
and the CRT!

So I have no more questions about warning C4251, at the moment... Thanks
again, Doug!


Kind regards, Niels