Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Does anyone know what this text means? (related to C4251 warning)

6 views
Skip to first unread message

Anonymous

unread,
Oct 31, 2007, 11:25:46 PM10/31/07
to
On MS site: http://msdn2.microsoft.com/en-us/library/esew7y1w(VS.80).aspx

is the following garbled rambling:

"You can avoid exporting classes by defining a DLL that defines a class
with virtual functions, and functions you can call to instantiate and
delete objects of the type. You can then just call virtual functions on
the type."


Does anyone actually understand what is being said?. A simple example
would help.

Doug Harrison [MVP]

unread,
Nov 1, 2007, 12:48:47 AM11/1/07
to

Off the top of my head:

#ifdef COMPILING_X_DLL
#define X_EXPORT __declspec(dllexport)
#else
#define X_EXPORT __declspec(dllimport)
#endif

class X
{
protected:

X();
virtual ~X();

private:

// Copyguard
X(const X&);
void operator=(const X&);

public:

virtual void f1();
virtual void f2();
virtual void f3();

private:

// Non-virtual implementation functions

public:

X_EXPORT static X* Create();
X_EXPORT static void Destroy(X*);
};

Then in x.cpp, implement all the functions except those in the Copyguard
section. If you need copying, you may have to implement those functions,
and if you want users to be able to make copies, you'll have to expand the
static section. You don't have to export the virtual functions, because
they are represented by pointers in the vtbl, and each object contains a
pointer (the vptr) to this table. Thus, you don't link to those functions
by name, and that's why you don't have to export them. You do have to
export the creation and deletion functions, because you have to be able to
link to them by name.

Of course, the weakness of following the documentation you quoted to the
letter is that derived classes can't call X::f1(), because that's a
statically bound call and does require linking by name. You can work around
that by adding X_EXPORT to the front of your virtual functions. But then
you're just about at the point where you might as well have exported the
whole class, which is what I recommend doing if you want the thing to act
like a C++ class instead of a COM-style interface. As long as you link
everyone to the same CRT DLL and consider this usage equivalent to static
linking WRT compilation dependencies, for the most part, it'll work fine,
and you can get rid of the Create/Destroy functions, as well as all the
individual function exports, and it'll "just work".

--
Doug Harrison
Visual C++ MVP

David Wilkinson

unread,
Nov 1, 2007, 5:36:56 AM11/1/07
to

Doug:

The way I do this is a bit more COM-like (I think; I don't really know COM):

// Interface (no constructor or destructor needed)
class IBase
{


public:
virtual void f1();
virtual void f2();
virtual void f3();

};


// Implementation
class MyClass: public IBase
{


public:
virtual void f1();
virtual void f2();
virtual void f3();

// other stuff
};

The exported factory functions are stand-alone functions:

IBase* CreateClass()
{
return new MyClass;
}

void DestroyClass(IBase* pBase)
{
delete (MyClass*)pBase;
}

This method is compiler independent.

--
David Wilkinson
Visual C++ MVP

Ben Voigt [C++ MVP]

unread,
Nov 1, 2007, 9:38:35 AM11/1/07
to
BTW David's way is what the article is referring to. Inheritance is done
via aggregation and implementing the same public interface. The actual
concrete class is not present in the public header file, only the pure
interface (contains only pure virtual functions) is. The factory functions
must be global to avoid name mangling issues, they would be prototyped in
the public header file. Destruction should be a Dispose function in the
v-table which calls "delete this;", avoiding the cast, or if reference
counting is used then AddRef/Release functions in the v-table.

Doug's way, although it might avoid the warning, does all the things the
warning is designed to discourage (exports class members, violates
one-definition rule, etc).


Anonymous

unread,
Nov 1, 2007, 12:31:52 PM11/1/07
to


Just to make sure we are 'on the same page':

From what you say above, David's example header should include lines
somewhat like this:

// Header
IBase* DECLSPEC_MACRO CreateClass() ;
void DECLSPEC_MACRO DestroyClass(IBase* pBase) ;

Where DECLSPEC_MACRO simply evaluates to a
__declspec(dllimport/dllexport) as the case may be

Is my understanding correct ?

Also, could you please explain this paragraph in your response:

"Destruction should be a Dispose function in the v-table which calls
"delete this;"

Surely, if the Construction/Destruction are global functions, then they
can't have a 'this' pointer?

Dis you make a mistake, or am I missing something ?

Ben Voigt [C++ MVP]

unread,
Nov 1, 2007, 2:16:01 PM11/1/07
to

"Anonymous" <no.r...@here.com> wrote in message
news:MYidnefeK_u5nbfa...@bt.com...

>
>
> Ben Voigt [C++ MVP] wrote:
>> BTW David's way is what the article is referring to. Inheritance is done
>> via aggregation and implementing the same public interface. The actual
>> concrete class is not present in the public header file, only the pure
>> interface (contains only pure virtual functions) is. The factory
>> functions must be global to avoid name mangling issues, they would be
>> prototyped in the public header file. Destruction should be a Dispose
>> function in the v-table which calls "delete this;", avoiding the cast, or
>> if reference counting is used then AddRef/Release functions in the
>> v-table.
>>
>> Doug's way, although it might avoid the warning, does all the things the
>> warning is designed to discourage (exports class members, violates
>> one-definition rule, etc).
>
>
> Just to make sure we are 'on the same page':
>
> From what you say above, David's example header should include lines
> somewhat like this:
>
> // Header
> IBase* DECLSPEC_MACRO CreateClass() ;
> void DECLSPEC_MACRO DestroyClass(IBase* pBase) ;

Pretty much, unless you use self-destruction.

Also, it's common to use an out parameter instead of a return value for the
new object, like:

HRESULT DECLSPEC_MACRO CreateClass(IBase** pRetval);

>
> Where DECLSPEC_MACRO simply evaluates to a __declspec(dllimport/dllexport)
> as the case may be

and MY_LIBRARY_DLL is a better name than DECLSPEC_MACRO

>
> Is my understanding correct ?
>
> Also, could you please explain this paragraph in your response:
>
> "Destruction should be a Dispose function in the v-table which calls
> "delete this;"
>
> Surely, if the Construction/Destruction are global functions, then they
> can't have a 'this' pointer?
>
> Dis you make a mistake, or am I missing something ?

This would be a virtual member function Dispose instead of a global
destruction function, because the global destruction function has to do a
cast, whereas a member function is pretty well assured that the object is
the correct type.


Doug Harrison [MVP]

unread,
Nov 1, 2007, 4:55:58 PM11/1/07
to
On Thu, 1 Nov 2007 08:38:35 -0500, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>BTW David's way is what the article is referring to. Inheritance is done
>via aggregation and implementing the same public interface.

That's not "inheritance" in the C++ sense of the word.

>The actual
>concrete class is not present in the public header file, only the pure
>interface (contains only pure virtual functions) is. The factory functions
>must be global to avoid name mangling issues, they would be prototyped in
>the public header file.

They must also be exported, as the static member functions were in my
class.

>Destruction should be a Dispose function in the
>v-table which calls "delete this;", avoiding the cast, or if reference
>counting is used then AddRef/Release functions in the v-table.
>
>Doug's way, although it might avoid the warning, does all the things the
>warning is designed to discourage (exports class members, violates
>one-definition rule, etc).

It doesn't just "avoid the warning". What I talked about in the last
paragraph of my message lets you use the class as a real C++ class, instead
of some clumsy COM simulation. Not everything is a nail.

I've just read the documentation the OP linked to, and it's confused in all
its admonitions about "static data". What it's talking about is *template*
static data, and that's only tangentially related to __declspec(dllexport),
in that dllexported classes that contain or derive from templates that have
static data can run into trouble due to duplication of template static data
if two or more modules end up instantiating the template. (This is actually
its own problem, existing independently of the __declspec interaction, e.g.
in VC6, you couldn't pass a std::map object between two modules due to that
class template's use of static data.) There are essentially two approaches
to avoiding that problem:

1. You can ensure that the template instantiation only occurs in the module
implementing the dllexported class.

2. You can explicitly instantiate all the template specializations you use
and dllexport them from some DLL. The C4251 docs link to a KB article
describing this.

Even if you apply these solutions, everyone has to play along with them,
because if a module that applies the solution shares an affected object
with a module that does not, you will have the same problem.

Where did what I posted violate the ODR, BTW?

Ben Voigt [C++ MVP]

unread,
Nov 1, 2007, 6:45:41 PM11/1/07
to

"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:pbcki3p750upnqmsi...@4ax.com...

> On Thu, 1 Nov 2007 08:38:35 -0500, "Ben Voigt [C++ MVP]"
> <r...@nospam.nospam> wrote:
>
>>BTW David's way is what the article is referring to. Inheritance is done
>>via aggregation and implementing the same public interface.
>
> That's not "inheritance" in the C++ sense of the word.

It isn't type derivation, but it is inheritance in the OOP sense of the
word.

[snip]

>>Doug's way, although it might avoid the warning, does all the things the
>>warning is designed to discourage (exports class members, violates
>>one-definition rule, etc).
>
> It doesn't just "avoid the warning". What I talked about in the last
> paragraph of my message lets you use the class as a real C++ class,
> instead
> of some clumsy COM simulation. Not everything is a nail.

That's misleading. What you could say is "it's a real Visual C++ 8.0 class
dynamically linking the debug runtime library, with 4-byte packing, and
STL_CHECKED_ITERATORS=0"... if those are in fact the compiler options used.
Whereas the source code for a real C++ class can be used in any C++ program
and compiled with any C++ standard-compliant compiler.

[snip]

>
> Where did what I posted violate the ODR, BTW?

The definition of class X is different between the provider and consumer.

Every single use of dllimport/dllexport on a type violates the ODR.
Sometimes you can get away with it, sometimes not.

Anonymous

unread,
Nov 1, 2007, 8:34:23 PM11/1/07
to

All this seems unnecessarily complicated - it sounds like reinventing
the (COM) wheel. Maybe I should just use the PImpl Idiom (typesafe
opaque ptr) to move all of the private data from the header file into
the implementation - that will certainly make the compiler shut up about
C4251 warnings ?

Doug Harrison [MVP]

unread,
Nov 1, 2007, 10:52:25 PM11/1/07
to
On Fri, 02 Nov 2007 00:34:23 +0000, Anonymous <no.r...@here.com> wrote:

>All this seems unnecessarily complicated - it sounds like reinventing
>the (COM) wheel.

To a large extent, that's exactly what it is.

>Maybe I should just use the PImpl Idiom (typesafe
>opaque ptr) to move all of the private data from the header file into
>the implementation - that will certainly make the compiler shut up about
>C4251 warnings ?

Yes, using the PImpl idiom will avoid C4251, and so will #pragma
warning(disable). For the most part, this warning can be ignored. It's an
issue primarily when class templates that have static data are involved.[*]
See my reply to Ben for more on that. Also, when exporting whole classes,
you must do as I said in my first reply to you, namely, "link everyone to


the same CRT DLL and consider this usage equivalent to static linking WRT

compilation dependencies."

[*] Another way C4251 can be legitimate is if an inline function in a
dllexported class calls a function in a non-exported class. ISTR that VC6
would inline those functions even though their class is exported, and that
would lead to a linker error, because the non-exported function couldn't be
found. VC2005 does not appear to inline such functions, so that leaves
template static data as the only real issue.

Doug Harrison [MVP]

unread,
Nov 1, 2007, 11:12:29 PM11/1/07
to
On Thu, 1 Nov 2007 17:45:41 -0500, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>> Where did what I posted violate the ODR, BTW?
>
>The definition of class X is different between the provider and consumer.
>
>Every single use of dllimport/dllexport on a type violates the ODR.

Can you write a program that can detect it and cares about it? Since "every
single use violates the rule", please restrict yourself to the simplest
type imaginable. :)

Listen, when you use __declspec(dllexport|dllimport), you're no longer
writing in Standard C++. Someone who wants to use the feature doesn't care
about inconsequential violations of the ODR; he cares only that the program
behaves as he expects a C++ program to behave. I'm happy to talk about
relevant ways in which expectations are violated, because they're important
for people using the feature to understand.

Ben Voigt [C++ MVP]

unread,
Nov 6, 2007, 4:17:20 PM11/6/07
to

"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:384li3hmlhnmrfud3...@4ax.com...

> On Thu, 1 Nov 2007 17:45:41 -0500, "Ben Voigt [C++ MVP]"
> <r...@nospam.nospam> wrote:
>
>>> Where did what I posted violate the ODR, BTW?
>>
>>The definition of class X is different between the provider and consumer.
>>
>>Every single use of dllimport/dllexport on a type violates the ODR.
>
> Can you write a program that can detect it and cares about it? Since
> "every
> single use violates the rule", please restrict yourself to the simplest
> type imaginable. :)

#if BAD_DLL_BUILD
#define BAD_DLL __declspec(dllexport)
#else
#define BAD_DLL __declspec(dllimport)
#endif

BAD_DLL class Badness
{
char first;
double second;
public:
double getValue() { return second; }
};

First up, the ODR is violated because BAD_DLL is defined differently in each
compilation unit.

Practically, because getValue is defined inside the class declaration, it is
automatically marked for inlining. Therefore each compile unit will
independently calculate the class layout. Since the class layout may not be
the same for the DLL and EXE (only the v-table layout is part of the ABI and
guaranteed to remain the same), there's a problem.

Doug Harrison [MVP]

unread,
Nov 6, 2007, 7:38:19 PM11/6/07
to
On Tue, 6 Nov 2007 15:17:20 -0600, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>#if BAD_DLL_BUILD
>#define BAD_DLL __declspec(dllexport)
>#else
>#define BAD_DLL __declspec(dllimport)
>#endif
>
>BAD_DLL class Badness
>{
> char first;
> double second;
>public:
> double getValue() { return second; }
>};
>
>First up, the ODR is violated because BAD_DLL is defined differently in each
>compilation unit.

I'll say it again: Listen, when you use __declspec(dllexport|dllimport),


you're no longer writing in Standard C++. Someone who wants to use the
feature doesn't care about inconsequential violations of the ODR; he cares
only that the program behaves as he expects a C++ program to behave. I'm
happy to talk about relevant ways in which expectations are violated,
because they're important for people using the feature to understand.

(Key terms are "inconsequential violations" and "relevant ways". You are at
best talking about the former, and in no way, the latter.)

>Practically, because getValue is defined inside the class declaration, it is
>automatically marked for inlining. Therefore each compile unit will
>independently calculate the class layout. Since the class layout may not be
>the same for the DLL and EXE (only the v-table layout is part of the ABI and
>guaranteed to remain the same), there's a problem.

I'll ask you again: Can you write a program that can detect it and cares
about it? ("It" being this purported ODR violation.) In case you don't
realize it, you haven't demonstrated anything; you've just made some new
unsubstantiated claims.

NB: You'll discover your glaringly obvious syntax error when you try to
write this program. Anybody bold enough to categorically proclaim "BAD_DLL"
ought to be able to write this program and demonstrate that there is an
actual problem. It's not a lot to ask. However, I hope you realize anyone
who understands the feature can write "GOOD_DLL"; indeed, MS uses
__declspec(dllexport|dllimport) in the C and C++ DLLs to export the common
basic_string specializations, std::exception, and various other classes. So
even if you are able to contrive a "BAD_DLL", I expect to find you've used
the feature incorrectly.

Ben Voigt [C++ MVP]

unread,
Nov 7, 2007, 9:22:33 AM11/7/07
to

"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:i5t1j3ptcmk9ug673...@4ax.com...

Yes, using pragma pack or any of a number of other options that affect the
class layout but work correctly when used consistently within a DLL, except
for dllexport types. As I said, only the v-table layout is part of the ABI
and is guaranteed to be the same in different DLLs.

>
> NB: You'll discover your glaringly obvious syntax error when you try to
> write this program. Anybody bold enough to categorically proclaim
> "BAD_DLL"
> ought to be able to write this program and demonstrate that there is an
> actual problem. It's not a lot to ask. However, I hope you realize anyone
> who understands the feature can write "GOOD_DLL"; indeed, MS uses
> __declspec(dllexport|dllimport) in the C and C++ DLLs to export the common
> basic_string specializations, std::exception, and various other classes.
> So
> even if you are able to contrive a "BAD_DLL", I expect to find you've used
> the feature incorrectly.

I see I caused confusion by naming my library "Ben's Awkward Demonstration"
because the acronym looks like the word bad.

Anyway, Microsoft using dllexport on types in the standard library causes no
end of problems, which frequently appear in this newsgroup.

Doug Harrison [MVP]

unread,
Nov 7, 2007, 12:40:25 PM11/7/07
to
On Wed, 7 Nov 2007 08:22:33 -0600, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>Yes, using pragma pack or any of a number of other options that affect the
>class layout but work correctly when used consistently within a DLL, except
>for dllexport types.

What do you mean, "except for dllexport types"?

If you use #pragma pack inconsistently on types for which it matters, you
are causing undefined behavior:

1. You can easily observe this within a single module by using different
packing in two translation units for a normal, non-dllexport type.

2. You can easily observe this for non-dllexport types shared between
modules. For example, there were (once) bugs due to inconsistent packing
affecting Windows's <winsock2.h> header and KEY_EVENT_RECORD type.

I hope you can see that problems like this exist independently of
dllexport.

>I see I caused confusion by naming my library "Ben's Awkward Demonstration"
>because the acronym looks like the word bad.

The problem is, you didn't "demonstrate" anything.

>Anyway, Microsoft using dllexport on types in the standard library causes no
>end of problems, which frequently appear in this newsgroup.

Then you should be able to provide numerous examples of "Microsoft using
dllexport on types in the standard library causing no end of problems".

Ben Voigt [C++ MVP]

unread,
Nov 13, 2007, 6:03:28 PM11/13/07
to

"Doug Harrison [MVP]" <d...@mvps.org> wrote in message
news:58p3j31qpn017qk9u...@4ax.com...

> On Wed, 7 Nov 2007 08:22:33 -0600, "Ben Voigt [C++ MVP]"
> <r...@nospam.nospam> wrote:
>
>>Yes, using pragma pack or any of a number of other options that affect the
>>class layout but work correctly when used consistently within a DLL,
>>except
>>for dllexport types.
>
> What do you mean, "except for dllexport types"?
>
> If you use #pragma pack inconsistently on types for which it matters, you
> are causing undefined behavior:
>
> 1. You can easily observe this within a single module by using different
> packing in two translation units for a normal, non-dllexport type.

True, but this can be (and in the newest versions of VC++ it usually is)
caught by the linker.

When you add dllexport to the mix, the difficult of matching settings
increases exponentially because you now have to match multiple binaries from
multiple vendors...

>
> 2. You can easily observe this for non-dllexport types shared between
> modules. For example, there were (once) bugs due to inconsistent packing
> affecting Windows's <winsock2.h> header and KEY_EVENT_RECORD type.
>
> I hope you can see that problems like this exist independently of
> dllexport.
>
>>I see I caused confusion by naming my library "Ben's Awkward
>>Demonstration"
>>because the acronym looks like the word bad.
>
> The problem is, you didn't "demonstrate" anything.
>
>>Anyway, Microsoft using dllexport on types in the standard library causes
>>no
>>end of problems, which frequently appear in this newsgroup.
>
> Then you should be able to provide numerous examples of "Microsoft using
> dllexport on types in the standard library causing no end of problems".

Specifically, people using binary third-party libraries that use STL objects
in the public API, that then prevent the consumer (programmer, not end-user)
from upgrading to a new compiler.

People wanting/needing to use two such libraries, that haven't used
identical settings to each other.

Ben Voigt [C++ MVP]

unread,
Nov 13, 2007, 6:36:17 PM11/13/07
to
>> Then you should be able to provide numerous examples of "Microsoft using
>> dllexport on types in the standard library causing no end of problems".

There's a brand new example right now in
microsoft.public.win32.programmer.kernel entitled "loading msvcr80.dll and
msvcr80d.dll"

It may not be using __declspec(dllexport), but it is the same problem --
DLLs making assumptions about each other's runtime library and compiler
settings.


Doug Harrison [MVP]

unread,
Nov 13, 2007, 8:30:21 PM11/13/07
to
On Tue, 13 Nov 2007 17:36:17 -0600, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>>> Then you should be able to provide numerous examples of "Microsoft using
>>> dllexport on types in the standard library causing no end of problems".
>
>There's a brand new example right now in
>microsoft.public.win32.programmer.kernel entitled "loading msvcr80.dll and
>msvcr80d.dll"
>
>It may not be using __declspec(dllexport)

What you said was, "Anyway, Microsoft using dllexport on types in the


standard library causes no end of problems, which frequently appear in this

newsgroup." I can't believe you're trying to back this up with an "example"
that doesn't involve dllexport and which comes from a different newsgroup,
no less.

>but it is the same problem --
>DLLs making assumptions about each other's runtime library and compiler
>settings.

I was really hoping you would produce several links. Then I would have
shown that there is a single answer to your "no end of problems," namely,
what I've been saying for years (not to mention in my first post in this
thread) about considering this use of DLLs equivalent to static linking for
compilation dependency purposes.

Ben Voigt [C++ MVP]

unread,
Nov 14, 2007, 9:42:42 AM11/14/07
to
> I was really hoping you would produce several links. Then I would have
> shown that there is a single answer to your "no end of problems," namely,
> what I've been saying for years (not to mention in my first post in this
> thread) about considering this use of DLLs equivalent to static linking
> for
> compilation dependency purposes.

I agree with that, except that "for compilation dependency purposes"
confuses the issue without adding any information IMHO.

However, that adds a lot of limitations, and avoiding those limitations was
the whole point of the text the OP quoted and asked about. Again, in my
opinion the language you used suggested that dllexport was just as good or
better than the method suggested by the MSDN article, and this just isn't
true in many (possibly most) situations.

The real question is "what value does dllexport have over static linking"
and aside from staggered loading, I can't think of anything. I'm pretty
sure it has no value whatsoever to most projects.

Doug Harrison [MVP]

unread,
Nov 15, 2007, 3:09:32 PM11/15/07
to
On Wed, 14 Nov 2007 08:42:42 -0600, "Ben Voigt [C++ MVP]"
<r...@nospam.nospam> wrote:

>I agree with that, except that "for compilation dependency purposes"
>confuses the issue without adding any information IMHO.

How is it unclear? I've been answering C4251 questions for a long time, and
I can't recall anyone asking for clarification, but that is the most
concise way I've found to put it. I typically go into quite a bit more
detail, along the lines of what I said in this thread in my first reply to
you and in my second reply to the OP. I don't know any better way to
capture the issue in one sentence.

>However, that adds a lot of limitations, and avoiding those limitations was
>the whole point of the text the OP quoted and asked about.

As I explained elsewhere in this thread, the documentation was concerned
with template static data. That's the _sole_ "limitation" it talked about.
As for the COM simulation suggestion, that's just one approach (the
documentation actually links to a KB article that explains how to dllexport
template specializations to avoid the problem), and as it prevents one from
using the class as a C++ class, which is why dllexport was being used in
the first place, it throws the baby out with the bath water. The OP would
seem to agree, as he replied to you:

<q>


All this seems unnecessarily complicated - it sounds like reinventing

the (COM) wheel. Maybe I should just use the PImpl Idiom (typesafe

opaque ptr) to move all of the private data from the header file into
the implementation - that will certainly make the compiler shut up about
C4251 warnings ?

</q>

In my reply, I explained why using the pimpl idiom is often overkill just
to silence C4251, when all you may need is #pragma warning(disable),
subject, of course, to what I say in my one sentence summary you find so
confusing.

>Again, in my
>opinion the language you used suggested that dllexport was just as good or
>better than the method suggested by the MSDN article, and this just isn't
>true in many (possibly most) situations.

Given that dllexport lets you use the class as a full-fledged C++ class
instead of a poor COM simulation, the former is infinitely better than the
latter if you want to use the class as a C++ class. That's effectively what
I said in my first reply to the OP, whose last paragraph was:

<q>


Of course, the weakness of following the documentation you quoted to the
letter is that derived classes can't call X::f1(), because that's a
statically bound call and does require linking by name. You can work around
that by adding X_EXPORT to the front of your virtual functions. But then
you're just about at the point where you might as well have exported the
whole class, which is what I recommend doing if you want the thing to act

like a C++ class instead of a COM-style interface. As long as you link


everyone to the same CRT DLL and consider this usage equivalent to static

linking WRT compilation dependencies, for the most part, it'll work fine,
and you can get rid of the Create/Destroy functions, as well as all the
individual function exports, and it'll "just work".

</q>

I deliberately differentiated the approaches. I deliberately mentioned
advantages and drawbacks of both, and I expanded at length in a subsequent
message on the one major issue (template static data) concerning what
you're trying to pass off as my "pet approach" or something. It's not my
pet approach. It just bugs me when someone who clearly _has_ a pet
approach, i.e. he thinks DLLs are only to be COM-style black boxes, and any
other usage is evil, tries to pass off groundless opinions (still waiting
on those examples) as if they were facts, when the facts are, lots
(probably many thousands) of programs use dllexported classes without any
problems. (See programs that use the C, C++, and MFC DLLs.)

>The real question is "what value does dllexport have over static linking"
>and aside from staggered loading, I can't think of anything. I'm pretty
>sure it has no value whatsoever to most projects.

It has the same value as static libraries, with the DLL advantages of
deterministic order of initialization of globals (DllMain restrictions
apply, of course), run-time code sharing (smaller code, more efficient
memory usage), and yes, the ability in some cases to fix bugs and make
other enhancements merely by replacing a DLL. It also allows one to be a
little more lax in controlling visibility of classes used internally by the
DLL, as one needn't worry about violating ODR rules between modules for
classes that aren't exposed in any way to DLL clients.

0 new messages