0
101 Dec 02, 2010 at 08:59

I am an amateur programmer updating a very amateur file structure I’ve been using for awhile and have run into some difficulties. Up until this point I’ve had all my code in multiple headers which I #included in a single source file. For convenience all my structs were defined all together in one of these headers. I am now trying to organise my code into paired source and headers and have spread the struct definitions out into the headers relevant to the code that references them. However some structs are fairly generic and are used broadly throughout the program. An example would be a vector struct. I want this struct defined in a header and then able to be ‘seen’ throughout the code. It seems that #including the header that contains its definition is not enough. If it is just a pointer to the struct in a function prototype it seems to also need a declaration in that header to make the compiler happy. If the vector struct is nested within another struct definition then it seems to need the vector struct redefined in that header. That’s ridiculous! Is this correct? Am I going about this the right way? I am using MS Visual Studio Express C++

#### 10 Replies

0
118 Dec 02, 2010 at 09:06

First off, you can use more than one #include line, so if you have something that’s needed everywhere, just put it in a separate include file and include that from either all the header files that need it.

To avoid issues with multiply-included files, you can use the common include guards:

#ifndef THISHEADER

... the header stuff here ...

#endif


that way, if the file gets included several times (from various header files, for instance), the contents will only get used once. the THISHEADER has to be unique for every header file; a common way is to name it HEADERFILE_H for headerfile.h and OTHERFILE_H for otherfile.h etc.

This is the easy way to do it. More preferable ways include source-side include guards, forward declarations in case the data structure is only used via a pointer, and preferably never including from include files, but those really become issues only when your project grows so large you start to worry about build times..

0
101 Dec 02, 2010 at 13:31

I think his problem has more to do with circular dependencies

// A.h
struct A
{
B * ptr;
};

// B.h
struct B
{
A * a;
};


Of course you could include A.h from B.h, and include B.h from A.h, but if you include A.h, it in turn includes B.h, and there you have a struct definition of B which nees A but which isn’t defined at that point.

The solution is, only include what you actually need. The fact of the matter is, A doesn’t need the definition of B, and neither does B need the definition of A. Actual definitions are only needed when accessing their members or when the compiler needs to know their size (which is if you use such a struct as a member of another struct). In above example, you only needs pointers. And all pointers are represented in the same way, so the only thing the compiler needs is that there exists an A when you’re using a pointer of A.

So, solution:

// A.h
struct B; // declaration of B, the compiler now knows that B exists, but does not know what it contains.

struct A
{
B * ptr;
};

// B.h
struct A;

struct B
{
A * a;
};


It now turns out that neither A nor B needs to include the other header.

That said:

If the vector struct is nested within another struct definition then it seems to need the vector struct redefined in that header. That’s ridiculous! Is this correct?

If you actually mean structs defined within other structs, then you have a problem. As these structs are members, you’ll need their encompassing struct definition:

// A.h
struct A
{
struct NestedA { };

B::NestedB * ptr;
};

// B.h
struct B
{
struct NestedB { };

A::NestedA * ptr;
};


Ok, now what? You can’t predeclare B in A because you’ll need B’s definition in order to access B::NestedB. Basically, you’re screwed. This is an unsolvable problem in C++*, and you should avoid these kinds of designs.

* Well, not literally unsolvable, you can apply some template trickery and make use of the two-phase name lookup paradigm to delay the lookup of the nested members until the actual use of the type at which point their both fully defined, but I don’t recommend it.

0
165 Dec 02, 2010 at 18:02

@Sol_HSA

To avoid issues with multiply-included files, you can use the common include guards:

0
101 Dec 02, 2010 at 20:58

@Reedbeta

I might be wrong but I was under the impression that #pragma once wasn’t technically standard. Not that it’s a big deal since it seems to be supported a lot.

0
165 Dec 02, 2010 at 21:00

It’s quite widely supported and if it isn’t part of the standard it ought to be, as it’s obviously better than #include guards when avalable. :yes:

0
101 Dec 03, 2010 at 03:35

That’s a great help thanks guys.

0
118 Dec 03, 2010 at 07:52

@Reedbeta

I was certain someone would find something to whine about, hence the last paragraph.

But yeah, I think include guards plus #pragma once is a better solution than external include guards. Will work everywhere and where the pragma is supported, faster compiles.

0
101 Dec 03, 2010 at 15:53

I have never actually seen benchmarks between regular guards and #pragma once, but I thought I read somewhere that some compilers simply recognized the standard include guards and acted as if a #pragma once is in that header (or more specificially it doesn’t reparse it when that macro is still defined when it’s reincluded).
@Reedbeta

It’s quite widely supported and if it isn’t part of the standard it ought to be, as it’s obviously better than #include guards when avalable. :yes:

Since it’s a #pragma directive it’s by definition not in the standard :)

0
101 Dec 06, 2010 at 09:04

@.oisyn

I have never actually seen benchmarks between regular guards and #pragma once, but I thought I read somewhere that some compilers simply recognized the standard include guards and acted as if a #pragma once is in that header (or more specificially it doesn’t reparse it when that macro is still defined when it’s reincluded).

I’d be very surprised if any major compilers didn’t do this.

0
101 Jan 28, 2011 at 07:05

Hay guys,
heeso is here.I have read this post and also visited the above link.It contains valuable information.I will use this information in future.