By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,946 Members | 741 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,946 IT Pros & Developers. It's quick & easy.

STL and DLL linkage (VC71/ VS2003) - Warning C4251

P: n/a
I am writing a shared object (Dll in Windows) and I am making extensive
use of the STL.

I am getting lots of warnings like this:

ClassA.h(139): warning C4251: 'ClassA::indexarray' : class
'std::vector<_Ty>' needs to have dll-interface to be used by clients of
class 'ClassA'
with
[
_Ty=int
]
My questions are:
1). Is this a VC7 (2003) specific problem?
2). How do I get rid of these warinings (without using #pragma disable
and without having to modify the sources of the STL)?
3). Is this fixed in VC8 (2005)?

Mar 16 '06 #1
Share this Question
Share on Google+
5 Replies


P: n/a
>I am writing a shared object (Dll in Windows) and I am making extensive use
of the STL.

I am getting lots of warnings like this:

ClassA.h(139): warning C4251: 'ClassA::indexarray' : class
'std::vector<_Ty>' needs to have dll-interface to be used by clients of
class 'ClassA'
with
[
_Ty=int
]
My questions are:
1). Is this a VC7 (2003) specific problem?
2). How do I get rid of these warinings (without using #pragma disable and
without having to modify the sources of the STL)?
3). Is this fixed in VC8 (2005)?


HI,

most of the time this warning is harmless and you can safely disable it.
Sometimes the warning is indicating a problem though.

There is a good in-depth explanation here:
http://www.unknownroad.com/rtfm/Visu...ningC4251.html

--
Kind regards,
Bruno van Dooren
br**********************@hotmail.com
Remove only "_nos_pam"
Mar 17 '06 #2

P: n/a
Bart Simpson wrote:
My questions are:
1). Is this a VC7 (2003) specific problem?
Warnings were designed to draw your attention to a possible problem.
Normally you want to export your classes, but in case of the STL you
simply can not. The STL is implemented purely in header files, and
therefore there is really not much code that requires exporting. You can
safely disregard the warning, but you must ensure that all your DLLs and
the EXE use the exact same compiler settings and the same STL
implementation, and also the dynamic version of the C runtime library
(due to the fact that when you use the static RTL, each DLL has its own
heap).

There are some compilers that don't report warning messages regarding
this, but VC++ does.
2). How do I get rid of these warinings (without using #pragma disable
and without having to modify the sources of the STL)?
This is one of those very few cases where you can't get rid of the
warnings without the #pragma. There are some macros on this site:
http://www.unknownroad.com/rtfm/Visu...ningC4251.html

But first, they don't work with any modern VC++ (7.1, 8.0). So I tried
to create my own version that worked (http://tweakbits.com/DllExport.h),
but I've run into problems. If two DLLs export the same STL container
(such as set<int>), I often get a conflict, which prevents linking. I
absolutely don't recommend that you try to export STL containers, like
using my DllExport.h. It's nothing else but a nasty hack. Just
disregarding those warning solves the problem -- because simply there is
no problem to be solved. If you really want to, you can try to export
vector<T>, but even then you'll keep getting warnings regarding
vector<T>::iterator, and vector<T>::allocator. Don't even attempt
exporting any other STL containers. In my experience, you'll just cause
more trouble trying to export STL classes than dealing with the warning.
3). Is this fixed in VC8 (2005)?


No, the warning is still there. The compiler doesn't know that it's
compiling STL, and if it was not STL, the warning would (could) be valid.

Tom
Mar 17 '06 #3

P: n/a
Tamas Demjen wrote :
This is one of those very few cases where you can't get rid of the
warnings without the #pragma. There are some macros on this site:
http://www.unknownroad.com/rtfm/Visu...ningC4251.html

But first, they don't work with any modern VC++ (7.1, 8.0). So I tried
to create my own version that worked (http://tweakbits.com/DllExport.h),
I also use this trick in _DEBUG only, because in release I don't use
dlls. I also recommend not to export STL classes, e.g. not to use STL
types in dll interfaces.
#define EXPORT_STL_VECTOR(declspec_, T_) \
template class declspec_ std::allocator<T_ >; \
template class declspec_ std::vector<T_ >;


I recently modified this macros not to explicitly instanciate the vector
if the declspec_ is not defined to __declspec( something ) because I ran
into troubles in some very special circumstances.
Since in my case I export the vector in _DEBUG only, it looks like:

#ifdef _DEBUG
#define EXPORT_STL_VECTOR(declspec_, T_) \
template class declspec_ std::allocator<T_ >; \
template class declspec_ std::vector<T_ >;
#else
#define EXPORT_STL_VECTOR(declspec_, T_)
#endif

Otherwise, with such a define:

#ifdef _DEBUG
....
#else
#define MYEXPORT /*empty*/
#endif

The EXPORT_STL_VECTOR( MYEXPORT, int ) would expand in Release in an
explicit specialisation:

template class std::allocator<int>;
template class std::vector<int>;

which is at least not very useful.
3). Is this fixed in VC8 (2005)?

No, the warning is still there. The compiler doesn't know that it's
compiling STL, and if it was not STL, the warning would (could) be valid.


I don't know how they can fix it. If you compile a dll which asks for a
std::string with VC++ 6 and use this same dll from your VC++ 8 app, you
will get a problem because each compiler uses its own std::string, and
VC++ 8 will call std::string::c_str() of its STL on a VC++ 6 std::string
instance...

Even with the same compiler it is a problem, because the dll and the exe
both use their own std::string specialisation. If they are compiled with
the same compiler, they use the same code, but this code is still
duplicated. In fact, you have 2 same std::string types in you process :
the dll one and the exe one. They can be the same, but they can also be
different. For example, if your dll compiles std::vector with
_SECURE_SCL defined, and your exe doesn't, your app may crash.
--
Aurélien Regat-Barrel
Mar 20 '06 #4

P: n/a
Aurelien Regat-Barrel wrote:
I also use this trick in _DEBUG only, because in release I don't use
dlls. I also recommend not to export STL classes, e.g. not to use STL
types in dll interfaces.


If the DLL is a plugin, I always make sure not to use STL in exported
functions. My plugin architecture is such that any C++ compiler can be
used to write plugins. I often use a pure C interface for plugins. I
also assume that the plugin uses a different memory allocator than the
main application. Handling that requires special attention, such as
passing an allocator function to the DLL, or the DLL has to expose a
cleanup function (create and free pairs).

But that's a major pain, and it requires wrappers. It's way too
time-consuming for everyday programming. I'm not going to stop using the
STL in my normal (non-plugin) modules. I'm not going to write my own
containers just because C++ is an inherently non-portable language
(binary portability is absolutely non-existant). It's mainly a fault of
the operating system for not providing transparent object-oriented DLL
architecture. .NET is supposed to fix that with mixed success.

When I modularize my application, I have a choice to use either LIB
files or DLLs. LIBs are not any better, because they still require that
you use the exact same compiler, same STL version, and same compiler
options. It's still easier to work with DLLs, because they're already
linked, and stable DLLs don't change. Also using DLLs it's possible to
fix a bug in an application without having to rebuild the entire
application. This increases long-term stability, as opposed to a full
rebuild, which would be needed with LIBs. It's a big advantage to me to
have dynamic modules, even if they can be tossed away when upgrading to
a new compiler. I know what I'm doing is not portable, and I can safely
disregard those warnings regarding not exporting STL classes.

It would be nice to be able to disable those warnings explicitly for
each line. Something that would tell the compiler that I acknowledged
that and I still want to do it, don't show that warning for that line
anymore. Disabling all warnings is not good, and leaving the warnings in
just makes everyone disregard all warnings after a while, because we get
overwhelmed. Right now the solution is to rebuild everything with full
warnings enabled once a month or so, but turn a lot of those warnings
off during everyday development. It's not an ideal situation.

Tom
Mar 20 '06 #5

P: n/a
Tamas Demjen a écrit :
Aurelien Regat-Barrel wrote:
I also use this trick in _DEBUG only, because in release I don't use
dlls. I also recommend not to export STL classes, e.g. not to use STL
types in dll interfaces.

If the DLL is a plugin, I always make sure not to use STL in exported
functions. My plugin architecture is such that any C++ compiler can be
used to write plugins. I often use a pure C interface for plugins. I
also assume that the plugin uses a different memory allocator than the
main application. Handling that requires special attention, such as
passing an allocator function to the DLL, or the DLL has to expose a
cleanup function (create and free pairs).

But that's a major pain, and it requires wrappers. It's way too
time-consuming for everyday programming. I'm not going to stop using the
STL in my normal (non-plugin) modules. I'm not going to write my own
containers just because C++ is an inherently non-portable language
(binary portability is absolutely non-existant). It's mainly a fault of
the operating system for not providing transparent object-oriented DLL
architecture. .NET is supposed to fix that with mixed success.


I don't understand why the OS is responsible of that, and how it could
help in solving it; .Net works with the same OS, and it solves it. But
it uses generics, which are instantiated at runtime. C++/CLI offers both
templates and generics... Hum... That's a good question : how does
C++/CLI deals with managed templates across different assemblies?

VC++ allows you to export a template instantiation, which is not a
common feature as far as I know. I my case, exporting std::vector and
boost::shared_ptr made the warning disappear.
When I modularize my application, I have a choice to use either LIB
files or DLLs. LIBs are not any better, because they still require that
you use the exact same compiler, same STL version, and same compiler
options. It's still easier to work with DLLs, because they're already
linked, and stable DLLs don't change. Also using DLLs it's possible to
fix a bug in an application without having to rebuild the entire
application. This increases long-term stability, as opposed to a full
rebuild, which would be needed with LIBs. It's a big advantage to me to
have dynamic modules, even if they can be tossed away when upgrading to
a new compiler. I know what I'm doing is not portable, and I can safely
disregard those warnings regarding not exporting STL classes.
When you fix a bug in a LIB, without touching to its interface, you only
need to relink your application, and not to perform a full rebuild. If
you use libraries (DLL/LIB) in order to modularize your application, in
my opinion, LIBS a better for redistribution because:

- you don't need to wonder about __declspec()
- they allow better optimisation from the compiler, smaller size (in
particular if each dll uses its own CRT, which is safer if you want
stability)
- they reduce the time needed to load your app (dynamic linking has a cost)
- your app is monolithic : less risks to loose a dll, better protection
against curious guys (crackers, competitors, ...), illegal reuse of your
dll etc...
- you don't expose internal structures : dlls interfaces can be very verbose
- you don't have to wonder about which version of each dll is installed

Even with a dll you must take care about the way you compile it, and how
you use it. In particular with memory. If each dll has its own CRT, you
must be very careful the way you alloc/free objets in your app. For
example, in my case, I had a crash when my app exited, because the dll
which gave me some (exported) shared_ptr was unloaded by Windows before
others dlls which then tried to free this ptrs...
It would be nice to be able to disable those warnings explicitly for
each line. Something that would tell the compiler that I acknowledged
that and I still want to do it, don't show that warning for that line
anymore. Disabling all warnings is not good, and leaving the warnings in
just makes everyone disregard all warnings after a while, because we get
overwhelmed. Right now the solution is to rebuild everything with full
warnings enabled once a month or so, but turn a lot of those warnings
off during everyday development. It's not an ideal situation.


You can put all the "safe code" in a separated unit and disable the
warning for this file only. It is an idea...

Regards

--
Aurélien Regat-Barrel
Mar 21 '06 #6

This discussion thread is closed

Replies have been disabled for this discussion.