473,406 Members | 2,954 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

Large scale C++ software design,

Large scale C++ software design, by John Lakos - people any good
recommendations to this book?

Jul 23 '05 #1
28 2386
Definitely worthwhile. /david :-)

Jul 23 '05 #2

davidru...@warpmail.net wrote:
Definitely worthwhile. /david :-)


Yep, I second that. :)

-shez-

Jul 23 '05 #3
puzzlecracker wrote:
Large scale C++ software design, by John Lakos
- people any good recommendations to this book?


This book was published in 1996
and contains a lot of obsolete advice.
For example, Chapter 2 Ground Rules,
Section 5 Redundant Include Guards, page 85,

Minor Design Rule
Place a redundant (external) include guard
around each preprocessor include directive
in every header file.

Today, we expect the C preprocessor to remember
idempotent header files and read them only once.
Jul 23 '05 #4

E. Robert Tisdale wrote:
puzzlecracker wrote:
Large scale C++ software design, by John Lakos
- people any good recommendations to this book?


This book was published in 1996
and contains a lot of obsolete advice.
For example, Chapter 2 Ground Rules,
Section 5 Redundant Include Guards, page 85,

Minor Design Rule
Place a redundant (external) include guard
around each preprocessor include directive
in every header file.

Today, we expect the C preprocessor to remember
idempotent header files and read them only once.

what would you supplement this book with? Any viable alternatives or
construction suggestions that would go on par with this book?

Jul 23 '05 #5
I would personally recommend Meyers, Dewhurst, and various books by
Sutter. However, none of these really address physical design in the
way that Lakos does.

Jul 23 '05 #6

E. Robert Tisdale wrote:
This book was published in 1996
and contains a lot of obsolete advice.
For example, Chapter 2 Ground Rules,
Section 5 Redundant Include Guards, page 85,

Minor Design Rule
Place a redundant (external) include guard
around each preprocessor include directive
in every header file.

Today, we expect the C preprocessor to remember
idempotent header files and read them only once.


What are you talking about? Is that specified in standard C++? Does
the following code compile for you?

blah.h
------
int somefunction() { return 9; }

blah.cpp
--------
#include <iostream>
#include "blah.h"
#include "blah.h"

int main() { std::cout << somefunction() << std::endl; }

I tried it on gpp and got "error: redefinition of 'int
somefunction()'". If it compiles for you, I'd really like to know what
compiler you're using.

Thanks,
-shez-

Jul 23 '05 #7
"Shezan Baig" <sh************@gmail.com> wrote...

E. Robert Tisdale wrote:
This book was published in 1996
and contains a lot of obsolete advice.
For example, Chapter 2 Ground Rules,
Section 5 Redundant Include Guards, page 85, ^^^^^^^^^
Minor Design Rule
Place a redundant (external) include guard ^^^^^^^^ around each preprocessor include directive
in every header file.

Today, we expect the C preprocessor to remember
idempotent header files and read them only once.
What are you talking about?


He is talking about advice John Lakos gave in his book.
Is that specified in standard C++?
Why should that matter? The Standard doesn't specify any
design guidelines nor does it say what features of a C++
compiler make a better competitor on today's market. If
the preprocessor remembers what headers it has already
included, the redundant guards become unnecessary.
Does
the following code compile for you?

blah.h
------
int somefunction() { return 9; }

blah.cpp
--------
#include <iostream>
#include "blah.h"
#include "blah.h"

int main() { std::cout << somefunction() << std::endl; }

I tried it on gpp and got "error: redefinition of 'int
somefunction()'". If it compiles for you, I'd really like to know what
compiler you're using.


No, what you presented here will certainly not compile.
However, if you add

#pragma once

to 'blah.h', some modern compilers will not preprocess it
again. The existence of 'once' pragma makes *external*
include guards unnecessary.

V
Jul 23 '05 #8
These small details are less important compared to the overall
methodology presented in the book. The main point is to recognize that
physical design is a separate problem from logical design, and then to
learn how to implement a physical design.

Jul 23 '05 #9
Victor Bazarov wrote:
However, if you add

#pragma once

to 'blah.h', some modern compilers will not preprocess it
again. The existence of 'once' pragma makes *external*
include guards unnecessary.


That worked! Cool, thanks!

-shez-

Jul 23 '05 #10
Shezan Baig wrote:
E. Robert Tisdale wrote:
This book was published in 1996
and contains a lot of obsolete advice.
For example, Chapter 2 Ground Rules,
Section 5 Redundant Include Guards, page 85,

Minor Design Rule
Place a redundant (external) include guard
around each preprocessor include directive
in every header file.

Today, we expect the C preprocessor to remember
idempotent header files and read them only once.
What are you talking about?
Is that specified in standard C++?
Does the following code compile for you?

blah.h
------
int somefunction() { return 9; }

blah.cpp
--------
#include <iostream>
#include "blah.h"
#include "blah.h"

int main() { std::cout << somefunction() << std::endl; }

I tried it on gpp
and got "error: redefinition of 'int somefunction()'".
If it compiles for you,
I'd really like to know what compiler you're using.


You are confused.
John Lakos might write:
cat blah.h #ifndef GUARD_BLAH_H // *internal* include guard
#define GUARD_BLAH_H 1
int somefunction() { return 9; }
#endif//GUARD_BLAH_H 1
cat blah.cpp

#include <iostream>
#ifndef GUARD_BLAH_H // *external* include guard
#include "blah.h"
#endif//GUARD_BLAH_H
#ifndef GUARD_BLAH_H // *external* include guard
#include "blah.h"
#endif//GUARD_BLAH_H

int main() { std::cout << somefunction() << std::endl; }

The redundant external include guards are not necessary
because, after the C preprocessor reads blah.h once,
it remembers that blah.h is idempotent
and it won't even attempt to read it a second time.
Jul 23 '05 #11
Victor Bazarov wrote:
No, what you presented here will certainly not compile.
However, if you add

#pragma once

to 'blah.h', some modern compilers will not preprocess it
again. The existence of 'once' pragma makes *external*
include guards unnecessary.

Still it can not be considered portable, and I wonder why at least the
2003 standard did not include this directive.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #12
puzzlecracker wrote:
Large scale C++ software design, by John Lakos - people any good
recommendations to this book?


The book is somewhat aged and predates modern C++ techniques
like template meta programming which are neither covered nor
can be addressed with the techniques in this book (partially
because compiler writers refuse to implement the complete
standard, in particular exporting templates). If you keep
this in mind, Lakos' book is excellent reading.

The discussion of the [redundant] external include guards
brought up in thread may be outdata after nearly 10 more years
but it is only one of many techniques Lakos uses to keep huge
project managable. Many of the other techniques have impacts
on the actual C++ code as well as on object oriented design
for achieving independent units.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 23 '05 #13
In message <ct**********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
John Lakos might write:
> cat blah.h

#ifndef GUARD_BLAH_H // *internal* include guard
#define GUARD_BLAH_H 1
int somefunction() { return 9; }
#endif//GUARD_BLAH_H 1
> cat blah.cpp

#include <iostream>
#ifndef GUARD_BLAH_H // *external* include guard
#include "blah.h"
#endif//GUARD_BLAH_H
#ifndef GUARD_BLAH_H // *external* include guard
#include "blah.h"
#endif//GUARD_BLAH_H

int main() { std::cout << somefunction() << std::endl; }

The redundant external include guards are not necessary
because, after the C preprocessor reads blah.h once,
it remembers that blah.h is idempotent
and it won't even attempt to read it a second time.


The C++ preprocessor has no notion of idempotency. (I have no idea
whether the C preprocessor does or does not, and it's off-topic here
anyway.) All it "remembers" is that the include-guard macro has been
defined.

If you mean "include guards should go inside the included file, not
outside", just say so.
--
Richard Herring
Jul 23 '05 #14
No, redundant guards go in the .h file only, not in the .cpp file. The
reason has more to do with reducing compile time than providing some
kind of protection against multiply defined symbols. /david

Jul 23 '05 #15
Ioannis Vranos wrote:
Victor Bazarov wrote:
No, what you presented here will certainly not compile.
However, if you add

#pragma once

to 'blah.h', some modern compilers will not preprocess it
again. The existence of 'once' pragma makes *external*
include guards unnecessary.


Still it can not be considered portable, and I wonder why at least the
2003 standard did not include this directive.


Pragmas are by definition implementation-defined.

There are two sides to the issue: following language rules and good
large-scale system design. They are orthogonal. If some compiler
features that aren't in the language proper allow you to achieve
a better result in the system design, who is to tell you not to use
it because "it can not be considered portable"? Who cares that it
is not portable if it does what it intends to do?

IOW, don't get hung up on portability.

V
Jul 23 '05 #16
da********@warpmail.net wrote:
No, redundant guards go in the .h file only, not in the .cpp file.


Well, then, they're not *redundant*, now, are they?

--
Mike Smith
Jul 23 '05 #17
Mike Smith wrote:
da********@warpmail.net wrote:
No, redundant guards go in the .h file only, not in the .cpp file.


Well, then, they're not *redundant*, now, are they?


They are: the idea is that you enclose each '#include' statement
in a header file with the same guards as the header file uses
internally. That is, if you omit the redundant guards, there will
be no semantic difference. However, the compiler does not need to
search and open the included header file if it was included before
due to the redundant guards.

For example:

/**/ // file: foo.h
/**/ #if !defined(FOO_H) // non-redundant guard
/**/ #define FOO_H
/**/ ...
/**/ #endif

/**/ // file: bar.h
/**/ #if !defined(BAR_H) // non-redundant guard
/**/ #define BAR_H
/**/ # if !defined(FOO_H) // <--- redundant guard!
/**/ # include "foo.h"
/**/ # endif
/**/ #endif

Now, is this an important technique? Probably not today: Some
compiler added a non-portable #pragma to tell the compiler about
headers which only need to be included once (you should, however,
still provide the non-redundant guards anyway to avoid portability
problems; on the other hand, adding these guards can be done
automatically quite easy). Other compilers, e.g. gcc, detect that
the header has include guards and include it once anyway which is,
BTW, one of the reasons why there is no intention whatsoever to
bless the '#pragma once' thing by the standard.

At the time of Lakos' writing the optimizations techniques were no
widespread and include hierarchies often nested quite deep. Combine
this with slower processing (the preprocessor needs to read the
whole file) and [slower] network file systems and you will see the
impact of this technique. However, he goes actually much further
and things become much more interesting: he shows how to organize
the code to make inclue statements obsolete without changing any
function or class just by taking advantage of the knowledge about
things really necessary for declarations to work. ... and he goes
beyond this to decouple classes even further making even more of
the preprocessor hacking unnecessary. The impact of the refactoring
(if you don't do it right from the start of the project) is
tremendous and goes far beyond mere compile-time (although that
really matters; around the time he released his book I worked in a
project where a single built of the system took about 16 hours):
you can change things much more freely if you decouple them
religously (actually, in the same project mentioned above, a change
to essentially an arbitrary class caused the need to recompile
everything, at least from make's perspective; guess how successful
that project was...).

If you are working on a bigger piece of software, Lakos' is still
a must-read, IMO. It may be irrelevant to average toy programs but
it is still relevant for large-scale projects! ... and, to some
extend, even to projects in a different language than C++ (which
also sheds some light on the importance of include guard thingy).
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.contendix.com> - Software Development & Consulting

Jul 23 '05 #18
Dietmar Kuehl wrote:
Mike Smith wrote:
da********@warpmail.net wrote:
No, redundant guards go in the .h file only, not in the .cpp file.


Well, then, they're not *redundant*, now, are they?

They are: the idea is that you enclose each '#include' statement
in a header file with the same guards as the header file uses
internally. That is, if you omit the redundant guards, there will
be no semantic difference.


And once you omit the redundant guards, then they can no longer be
*redundant*. The ones in the .cpp file are the redundant ones; once you
remove them, you're left with the ones in the .h file, which are *not*
redundant.

--
Mike Smith
Jul 23 '05 #19

Mike Smith wrote:
Dietmar Kuehl wrote:
Mike Smith wrote:
da********@warpmail.net wrote:

No, redundant guards go in the .h file only, not in the .cpp file.

Well, then, they're not *redundant*, now, are they?

They are: the idea is that you enclose each '#include' statement
in a header file with the same guards as the header file uses
internally. That is, if you omit the redundant guards, there will
be no semantic difference.


And once you omit the redundant guards, then they can no longer be
*redundant*. The ones in the .cpp file are the redundant ones; once

you remove them, you're left with the ones in the .h file, which are *not* redundant.


You don't put redundant guards in your .cpp files. You put them in
header files (when you include other header files).

Hope this helps,
-shez-

Jul 23 '05 #20
Shezan Baig wrote:
You don't put redundant guards in your .cpp files.
You put them in header files (when you include other header files).


This was a maintenance nightmare.
If you changed the name of the internal guard macro in a header file,
you had to change the name of the external guard macro to match
in every header or source file that included it.
Jul 23 '05 #21

E. Robert Tisdale wrote:
Shezan Baig wrote:
You don't put redundant guards in your .cpp files.
You put them in header files (when you include other header files).


This was a maintenance nightmare.
If you changed the name of the internal guard macro in a header file,
you had to change the name of the external guard macro to match
in every header or source file that included it.


Not really. Why would you change it? The name of the include guard is
derived from the name of the header file. There should be no need to
change it. Unless of course you change the name of your header file,
in which case you would *have* *to* grep for all references to it
anyway.

Hope this helps,
-shez-

Jul 23 '05 #22

E. Robert Tisdale wrote:
Shezan Baig wrote:
You don't put redundant guards in your .cpp files.
You put them in header files (when you include other header files).


This was a maintenance nightmare.
If you changed the name of the internal guard macro in a header file,
you had to change the name of the external guard macro to match
in every header or source file that included it.


Not really. Why would you change it? The name of the include guard is
derived from the name of the header file. There should be no need to
change it. Unless of course you change the name of your header file,
in which case you would *have* *to* grep for all references to it
anyway.

Hope this helps,
-shez-

Jul 23 '05 #23
Shezan Baig wrote:
E. Robert Tisdale wrote:
Shezan Baig wrote:
You don't put redundant guards in your .cpp files.
You put them in header files (when you include other header files).
This was a maintenance nightmare.
If you changed the name of the internal guard macro in a header file,
you had to change the name of the external guard macro to match
in every header or source file that included it.


Not really. Why would you change it?
The name of the include guard is derived from the name of the header file.


Where is it written that, "The name of the include guard
is derived from the name of the header file."
There should be no need to change it.
Unless of course you change the name of your header file, in which case,
you would *have* *to* grep for all references to it anyway.

Jul 23 '05 #24

E. Robert Tisdale wrote:
Where is it written that, "The name of the include guard
is derived from the name of the header file."


Sorry, I didn't make my point totally clear with that quote. I didn't
intend for it to mean "it *must* be derived from the header file", but
it is definitely highly recommended. See Lakos p82, paragraph 2.

Hope this helps,
-shez-

Jul 23 '05 #25
FYI, the technique is implemented something like this: for
everycomponent file "foo.h" the include guard is called INCLUDED_FOO.
Now, coupled with package prefixes, each component file is actually
called "my_foo.h" and "your_foo.h", and the include guards are
INCLUDED_MY_FOO and INCLUDED_YOUR_FOO. This way, all filenames, and all
include guard names are unique across the project (and hopefully the
company). /david

Jul 23 '05 #26
Shezan Baig wrote:
E. Robert Tisdale wrote:
Shezan Baig wrote:
You don't put redundant guards in your .cpp files.
You put them in header files (when you include other header files).


This was a maintenance nightmare.
If you changed the name of the internal guard macro in a header file,
you had to change the name of the external guard macro to match
in every header or source file that included it.


Not really. Why would you change it? The name of the include guard
is derived from the name of the header file. There should be no need
to change it. Unless of course you change the name of your header
file, in which case you would *have* *to* grep for all references to
it anyway.


One way the include guard names and the header names can get out of sync is when
a header is renamed but the internal include guards are not updated.

Jonathan

Jul 23 '05 #27
Victor Bazarov wrote:
Pragmas are by definition implementation-defined.

There are two sides to the issue: following language rules and good
large-scale system design. They are orthogonal. If some compiler
features that aren't in the language proper allow you to achieve
a better result in the system design, who is to tell you not to use
it because "it can not be considered portable"? Who cares that it
is not portable if it does what it intends to do?

IOW, don't get hung up on portability.

Yes, however still the standard could have adopted #pragma once as an
alternative to inclusion guards.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #28
Jonathan Turkanis wrote:
One way the include guard names and the header names can get out of sync is when
a header is renamed but the internal include guards are not updated.

I do not know about the embedded world, however in the PC world most
(all?) IDEs provide the ability of "(find and) replace all" so you can
change a text found anywhere in the project with another text.


--
Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 23 '05 #29

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Constandinos Mavromoustakis | last post by:
CFP: CLADE 2004-Challenges of Large Applications in Distributed Environments ------------------------------------------------- PhD student - Dept.Informatics at Aristotle University of...
36
by: Andrea Griffini | last post by:
I did it. I proposed python as the main language for our next CAD/CAM software because I think that it has all the potential needed for it. I'm not sure yet if the decision will get through, but...
2
by: Kymert persson | last post by:
Hi. I was wondering if there are any more C++ books along the lines of "Large scale C++ software design" by Lakos, J. I.e. concerning larger design issues in close relation to C++. I have made a...
14
by: Steven T. Hatton | last post by:
Is there a more or less accepted authority describing how to structure a project? I know Julie has asked about namespaces. That is certainly a part of my question, but I want to know about the...
9
by: Da~One | last post by:
This message has been posted to 2 groups, one to the VB.NET group, and the other to C#. I am trying to decide which language to commit to for a large scale project. I am looking for the input of...
12
by: al.cpwn | last post by:
I recently bought this book, and wanted some recommendations on what are the most important lessons one should learn from this book. i.e. something that comes up frequently in large C++ based...
16
by: marktxx | last post by:
I've finally gotten around to reading the book "Large-Scale C++ Software Design" by John Lakos. Has anyone documented what parts of this book are now obsolete due to C++ language changes such as...
6
by: razael1 | last post by:
Does anyone know of a good article dealing with organizing large class heirarchies? I've always had trouble with circular dependencies, global constants and variables, etc. Thanks.
22
by: Jesse Burns | last post by:
I'm about to start working on my first large scale site (in my opinion) that will hopefully have 1000+ users a day. ok, this isn't on the google/facebook scale, but it's going to be have more hits...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.