How to instantiate objects in a public include file

E

Ed J

In a public include file, how can I declare an object and instantiate an
object all in one line, avoid seemingly duplicate information? I am
typically used to doing something like the following, but I've never liked
having to provide two lines related to the same object:

extern MyClass obj1;
extern MyClass obj2;
#if defined( INSTANTIATE_OBJECTS )
MyClass obj1( 111 );
MyClass obj2( 222 );
#endif

In one and only one C++ file, I would define INSTATIATE_OBJECTS to force the
instantiate.

I'm hoping to find a C-preprocessor trick that would let me use a single
line to both declare and instantiate an object, depending on the value of a
preprocessor macro. For example, I could use something like this (if I
could embed a "//" comment into a macro definition):

#if defined( INSTANTIATE_OBJECTS)
#define DECLARE_VS_DEFINE
#else
#define DECLARE_VS_DEFINE ; //
#endif
extern MyClass obj1 DECLARE_VS_DEFINE ( 111 );
extern MyClass obj2 DECLARE_VS_DEFINE ( 222 );

Does such a preprocessor macro trick exist? Is there another way to do it?
It would have to work with the Visual C compiler and GNU GCC.

Thanks,

Ed Jubenville
 
V

Victor Bazarov

Ed said:
In a public include file, how can I declare an object and instantiate
an object all in one line, avoid seemingly duplicate information?[..]

Never instantiate an object in a header. As soon as the header is
included in more than one translation unit (and if it isn't why it
is a header, right?), you get the object defined more than once.

V
 
J

Jim Langston

Ed said:
In a public include file, how can I declare an object and instantiate
an object all in one line, avoid seemingly duplicate information? I
am typically used to doing something like the following, but I've
never liked having to provide two lines related to the same object:

extern MyClass obj1;
extern MyClass obj2;
#if defined( INSTANTIATE_OBJECTS )
MyClass obj1( 111 );
MyClass obj2( 222 );
#endif

In one and only one C++ file, I would define INSTATIATE_OBJECTS to
force the instantiate.

I'm hoping to find a C-preprocessor trick that would let me use a
single line to both declare and instantiate an object, depending on
the value of a preprocessor macro. For example, I could use
something like this (if I could embed a "//" comment into a macro
definition):
#if defined( INSTANTIATE_OBJECTS)
#define DECLARE_VS_DEFINE
#else
#define DECLARE_VS_DEFINE ; //
#endif
extern MyClass obj1 DECLARE_VS_DEFINE ( 111 );
extern MyClass obj2 DECLARE_VS_DEFINE ( 222 );

Does such a preprocessor macro trick exist? Is there another way to
do it? It would have to work with the Visual C compiler and GNU GCC.

As V says, you don't. That's why we have header files and source files.
Why can't you just put

MyClass obj1( 111 );
MyClass obj2( 222 );

in a .c file and include it in your project? That's the way the language is
designed.
 
E

Ed J

Victor said:
Never instantiate an object in a header. As soon as the header is
included in more than one translation unit (and if it isn't why it
is a header, right?), you get the object defined more than once.

The object doesn't get defined more than once if the programmer (me) follows
the rules:
1. In ordinary source (.c) files wishing access to the declarations, I
simply do:
#include "filename.h"
2. In one and only one source file, I define INSTANSTIATE_OBJECTS before
including the file, and it gives me the declaration and the instantiation:
#define INSTANTIATE_OBJECTS
#include "filename.h"

I've used this technique many times on simple uninitialized variables to
avoid the hassle of maintaining two different source files (the .h and .c)
with the same object names. A typical xyz.h file would contain something
like this:

#if defined( INSTANTIATE_XYZ_OBJECTS )
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int xyz1;
EXTERN int xyz2;

That single block of source code serves both the purpose of declaration and
instantiation of xyz1 and xyz2, depending on whether the including .c file
first declares INSTANTIATE_XYZ_OBJECTS. But this technique only works for
uninitialized variables. I'm trying to find a similar technique for
initialized variables.

Editorial... It is a pet peeve of mine that the C and C++ languages require
me to create two source code lines (one in a .c file, and one in a .h file)
associated with the same object name. Simply put, one source code line is
easier to maintain than two source code lines, especially when those two
source code lines must, by edict of C/C++, reside in separate files. That's
edict is a maintenance hassle that I would gladly circumvent if I knew how.

Any ideas?
 
D

dp1978x

[snip]

Something along the lines of:

#ifdef INSTANTIATE_XYZ_OBJECTS
# define XYZ_EXTERN
# define XYZ_ARGS(args) args
#else
# define XYZ_EXTERN extern
# define XYZ_ARGS(args)
#endif

// no args
XYZ_EXTERN MyClass (obj0a);
XYZ_EXTERN MyClass (obj0b) XYZ_ARGS (());

// 1 arg
XYZ_EXTERN MyClass (obj1) XYZ_ARGS ((111));

// 2 args
XYZ_EXTERN MyClass (obj2) XYZ_ARGS ((111, 222));

But as others have pointed out it's a BAD IDEA. There are plenty of
ways you can abuse the preprocessor, why stop there? You could just as
well move all your source code into "headers" and conditionally
compile-out function bodies depending on some macro. Or "#define BEGIN
{" so it looks more like Pascal. Think of the sanity of the next guy
who will be maintaining this code. In your example trying to grep the
source files for these globals' definitions won't work anymore; the
meaning of these weird macros is not obvious, etc.

D.
 
J

jason.cipriani

The object doesn't get defined more than once if the programmer (me) follows
the rules:
1. In ordinary source (.c) files wishing access to the declarations, I
simply do:
#include "filename.h"
2. In one and only one source file, I define INSTANSTIATE_OBJECTS before
including the file, and it gives me the declaration and the instantiation:
#define INSTANTIATE_OBJECTS
#include "filename.h"

This is -exactly- equivalent to just putting the object declarations
in the header and putting the definition in one of the source files
(the source file you #define INSTANTIATE_OBJECTS in). Except doing it
with precompiler macros is slightly more work than you need to be
doing, and also requires you to explain what you are doing to other
people reading your code (whereas declaring objects as extern,
possibly with a comment like "// defined in file.cpp", is clear and
concise).
I've used this technique many times on simple uninitialized variables to
avoid the hassle of maintaining two different source files (the .h and .c)
with the same object names. A typical xyz.h file would contain something
like this:

It depends on how you look at it I guess. If you are going by "number
of files" then I guess having a .h file is "better" than having both a
source and a header. If you are going by "lines of code", you are
probably typing more with your preprocessor stuff. Also in either
case, you still have the dependency on a given source file. With your
method, if you remove the source file that #defines
INSTANTIATE_OBJECTS, you have to put that #define somewhere else. With
the other method, you still have to compile the source file with the
definitions into the project -- but at least it's clear that
"globals.cpp" matches "globals.h", rather than you saying "well if
something_unrelated.cpp isn't compiled then the objects declared in
globals.h won't be defined unless you move such and such preprocessor
definition to another arbitrary source file".

Both C and C++ have constructs and mechanisms ("extern", and the
linker) to cleanly and clearly do -precisely- what you are doing with
precompiler macros.
#if defined( INSTANTIATE_XYZ_OBJECTS )
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN int xyz1;
EXTERN int xyz2;

That single block of source code serves both the purpose of declaration and
instantiation of xyz1 and xyz2, depending on whether the including .c file
first declares INSTANTIATE_XYZ_OBJECTS.

Until somebody sees that you only named it "EXTERN", and starts using
EXTERN as a substitution for the real extern, expecting it to behave
sanely. If you insist on doing it this way instead of just defining
the objects in another source file, at least pick a better macro name
than EXTERN.
But this technique only works for
uninitialized variables. I'm trying to find a similar technique for
initialized variables.

You do it like this:

header.h:

extern int xyz1;
extern int xyz2;

one_source_file.cpp:

int xyz1 = 400;
int xyz2 = 234;

Again, if you insist on doing it with precompiler macros, you would do
this:

extern int xyz1;
extern int xyz2;
#ifdef INSTANTIATE_XYZ_OBJECTS
int xyz1 = 400;
int xyz2 = 234;
#endif

Having the declaration and definition in the same source file won't
cause any problems, there is no need to put the "extern int"
declarations in an #else block. But again, since you are only
#defining INSTANTIATE_XYZ_OBJECTS in a single source file before
#including that header, you don't have to bother with the preprocessor
at all -- just put the definitions right in that source file.
Editorial... It is a pet peeve of mine that the C and C++ languages require
me to create two source code lines (one in a .c file, and one in a .h file)
associated with the same object name. Simply put, one source code line is
easier to maintain than two source code lines, especially when those two
source code lines must, by edict of C/C++, reside in separate files. That's
edict is a maintenance hassle that I would gladly circumvent if I knew how.

The reason for this is that you need to have the declaration of an
object available so that the compiler knows it exists, and thus knows
the type of it and can compile your code. However, the object itself
is only defined in one translation unit. Declaration and definition
are two separate concepts. There is no other alternative. Let's say
that "declarations" didn't exist and you had to define everything
everywhere. What happens if you put:

int i = 3;

In a header, and that serves as both declaration and definition? Then
you compile multiple source files that use it. Then you change it to:

int i = 4;

And recompile only some of the source files. Or if it is a variable,
such as errno, that is defined in a library elsewhere (where you have
no control over the initialization of it -- yet you would still be
"initializing" it to a certain value in errno.h). A situation like
that would become a maintenance nightmare.

You are already running into a situation where you have to maintain a
separate declaration and definition for variables (you have to do this
with functions, too -- you have to have *some* way of saying "this
function exists" without repeating the code for it in every header you
use it in). As you can see, it actually *is* useful to have separate
declarations and definitions -- this completely solves your problem of
wanting to use initialized data in multiple source files. You may want
to consider removing that pet peeve from your list of pet peeves!
Any ideas?

So what it comes down to is: use the language features that are
already in place for doing exactly what you are trying to do. Declare
variables, as extern, in headers, define them in a single source file,
and don't use the preprocessor to emulate a feature that the language
already has.

Jason
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top