Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > C++ Project Organization Guidelines

Reply
Thread Tools

C++ Project Organization Guidelines

 
 
Steven T. Hatton
Guest
Posts: n/a
 
      07-26-2005
I think Danny was one cup of coffee shy of full consciousness when he wrote
this, but the gist of it makes sens to me:

"C++ Project Organization Guidelines
Last updated May 26, 2005.
http://www.informit.com/guides/conte...lus&seqNum=175
Last week's article about inline functions subtly brought into the limelight
another important issue, namely how to organize the files of a typical C++
program, or project. This week I discuss this issue and answer the
following questions: How to decide which code components should be included
in a header file and which ones belong to a source file? How many files
should be used in a project have[sic]?"

....

"Poorly-organized projects seldom succeed. Proper organization of project
units, consistent and intelligible file naming conventions and a reliable
configuration management tool (a topic which I didn't discuss here) are
prerequisites for a project's successful completion. Of course, these
measures can't replace talented and experienced developers and meticulous
design. Yet, unlike the latter, project organization is rarely discussed in
programming books."


//----------------------------------------------------------------------
This is the kind of discussion I was hoping to find in Sutter and
Alexanderescu's _Coding Standards_, but didn't. I believe C++ programmers
tend to avoid this kind of discussion because it's too much like politics
and religion. I also believe it's a topic overdue for serious discussion.

I actually don't believe he went nearly far enough. For example, I believe
it is advisable to organize a project into namespaces with file locations
reflecting the namespace hierarchy, and file names reflecting (in general)
class names.

Here's one possible way to arrange a project which I find attractive.
Tue Jul 26 00:23:21:> find . -type d | grep -v /.svn
..
../bin
../doc
../lib
../src
../src/diagram
../src/mtree
../src/osgQt
../src/patControl
../src/rstest
../src/osgqttest
../src/widgets
../build
../build/diagram
../build/mtree
../build/osgQt
../build/patControl
../build/rstest
../build/osgqttest
../build/widgets
../include
../include/math
../include/util
../include/control
../include/diagram
../include/mtree
../include/osgQt
../include/patControl
../include/rstest
../include/osgqttest
../include/widgets

The advantage to splitting src and include into too parallel hierarchies is
that it helps ensure the dependencies are actually separated. Each
namespace has its own build directory which produces its own libraries and
or executables. The executables are placed in ./bin and the libraries are
placed in ./lib. I try to link against the libraries in ./lib rather than
the ones in the build tree because that treats them as they would be
treated in an installed environment.

The listing above has the following namespaces:
control
diagram
math
mtree
osgQt
osgqttest
patControl
rstest
util
widgets

Typically, I create one unit (see Danny's article) per class, and give the
files a name identical to the class name except that the file names have
extensions. The header guards typically (ideally) are of the form
_NAMESPACE_CLASSNAME_H_. This is one place where the Cpp can hold a subtle
gotcha. Suppose you just use the file name as the foundation for the
header guard, and have two files with the same name in different parts of
the project. Another problem arrises when I rename a class, and thence its
filename. If I forget to rename the header guard, and subsequently create
another class of the same name, I can end up excluding one of the two
before it is processed for the first time.

Sometimes I find myself creating namespace local functions, or a bunch of
tiny classes. When that happens, I try to put them all in one unit with
filenames corresponding to the namespace name.

There are probably many refinements I can still make on my project
organization strategies. For one, I need to strengthen the concept of
interface, and the separation between interface and implementation. This
applies to both classes, and to namespaces.

See for example, the Xerces project:
http://svn.apache.org/viewcvs.cgi/xe...c/xercesc/dom/

Note that they follow very closely the recommendations of Stroustrup
regarding the use of pure interfaces (ABCs). Ironically, this seems to
have originated with the Java implementation of Xerces, and was carried
over when (as I understand things) Xerces was ported to C++. Another point
worth mentioning is the use of #include <xercesc/dom/DOMAttr.hpp>, etc.,
which I would like to tell you reflects the namespace hierarchy (as it
would in my code), but, unfortunately, they use a #define to bracket their
namespaces, and I don't recall what that is defined as, nor where it's
defined.

Another point is that I believe it would be a good idea for C++ programmers
to try to agree on a file name extension convention. I personally
dislike .cpp because it's reminiscent of the C preprocessor, but I can get
over that. .h is problematic because there are subtle differences between
C and C++, and .h can be understood by a multilingual tool to mean a C
header file. I therefore favor .cpp and .hpp. Unfortunately, KDevelop
doesn't currently (correctly) support that option.

I have one critique of Danny's code. I don't believe he needs the
log.close() in the destructor:

// logfile.h
#include <fstream>
#include <string>
class Logfile
{
public: //member functions are declared but not defined:
Logfile(const std::string & path);
~Logfile();
//...
private:
std:fstream log;
std::string name;
};

// logfile.cpp
#include "logfile.h"
//definitions of functions declared in the .h file
Logfile::Logfile(const std::string & path) :name(path)
{
log.open(name.c_str());
bool success=log;
//..
}
Logfile::~Logfile()
{
log.close();
//..
}

Another suggestion some people might make is to use a pointer in the header
file so that there is no memory allocation required if it is simply
#included in another translation unit. In that case he would need a
destructor. I'm not sure of the ramifications of using an auto_ptr in the
class definition. Would that be superior to using a local data member or a
pointer to std:fstream?
--
If our hypothesis is about anything and not about some one or more
particular things, then our deductions constitute mathematics. Thus
mathematics may be defined as the subject in which we never know what we
are talking about, nor whether what we are saying is true.-Bertrand Russell
 
Reply With Quote
 
 
 
 
EventHelix.com
Guest
Posts: n/a
 
      07-26-2005
Another important thing to look into is the header file include
management.

The following article gives some tips about how to manage header
file includes in your project.

http://www.eventhelix.com/RealtimeMa...dePatterns.htm

--
EventStudio 2.5 - http://www.EventHelix.com/EventStudio
Generate Sequence Diagrams in PDF and Word EMF from plain text input

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Netbeans File Organization - Web Project LB Java 5 07-25-2008 05:55 PM
tidy project file organization (modules and tests) bramble Python 0 11-22-2007 08:53 PM
Project organization and import redux Hamilton, William Python 0 04-05-2007 03:42 PM
Project organization and import Martin Unsal Python 51 03-07-2007 05:56 PM
web project organization in eclipse noemail12000@yahoo.com Java 0 08-09-2006 03:50 PM



Advertisments