Programming Tips And Tricks
Many projects suffer poor compilation speed due to bad
dependency design of classes, over-inclusion, and worse problems. Something that is
built into the compiler, and may be of some help, is setting up your precompiled headers
properly. It's really easy to do. Just create two files, which we'll call
First.h and First.cpp. In First.cpp, have only one line which is:
#include "First.h"
Then in your First.h file, place any includes that you will want to automatically be
included in all your .cpp files in your project. In other words, anything that can
help you spend less time compiling, you can stick in here. However,
read the notes at the end of this section before going too wild about this.
That should do it. What you did was set up First.cpp to always create
the precompiled header and all the other files to use the .pch it created. This is also a
good way to know if you have a LONG build ahead of you, because First.cpp is
always compiled first if and only if the .pch is changing, which means every file gets
recompiled.
Notes:
The most flexible and easiest to implement solution is to set up a memory tracking module which overloads the void *operator new() function globally which turns around and calls your memory modules alloc function. Track your own memory with a simple linked list system and youll always know if theres memory left allocated simply by checking the list for nodes. Some people like to use a #define and pass in__LINE__ and __FILE__ for tracking the allocation line number and source files. This adds considerable flexibility to your memory manager, and makes it possible to track down memory leaks in no time. Make sure you also overload the void *operator new[]() function as well, if your compiler supports it, or your arrays may leak memory and not be tracked; usually an operator new[]() function will chain down to the normal operator new() function to allocate an array, so this may not be necessary, but is a good idea for completeness' sake.
Oftentimes, programmers dont pay a lot of attention to the cleanliness of their code until its going to be looked over by someone carefully. Even then, chances are they go back and pretty it up rather than writing it well the first time. Heres a brief synopsis of the keys to writing good code the first time.
Do Use: |
Dont Use: |
Why? |
static_cast<type>(var) |
(type)var |
The static_cast<>() operator is a type converter, which does not affect the const-ness of the variable. C-style casting can change the const-ness and type all at once, even accidentally. Static_cast<>() will also only allow you to cast from one related type to another. You can convert from float to int by static_cast<int>(a); where "a" is a float. You cant convert from an arbitrary class to another. Note that converting one const type to another still requires you specify it as static_cast<const type>(var). That always gets me. J |
const_cast<type>(var) |
(type)var |
When trying to modify an object which is declared const or has been passed as a const parameter, you can do it without using a C-style cast. Its typically a sign that your class interface is not well developed, but this is the right tool for the job. Also, these casting operators are great to grep through code and find out where people are making massive mistakes. J |
reinterpret_cast<type>(var) |
(type)var |
This is the big gun. If you really cant find any way to cast directly to what you are certain the object is, you can just bonk the compiler on the head and say, "Look, I know what it is, now do it." You can flip a floats bits with int functions with this if you like, or whatever. The only time we use this is when casting from one type to void and back to another type isnt worth typing. Yes, thats a legal way to get around reinterpret_cast in most cases, but not recommended. Cant grep for that. Still, this does not change const-ness of an object. Only const_cast<>() can do that. |
explicit |
Place this keyword directly
before constructor declarations in the class header file. The only constructors which
shouldnt have explicit are ones which allow types to be converted with another
constructor by the expected parameter type. If that doesnt make sense, consider you
are writing a FixedPoint class which approximates floating point numbers. If you have one
constructor which takes a float type, you might declare it as explicit so that an int will
not be converted to a float before being passed in. Instead, the compiler will issue an
error that there is no appropriate constructor. Instead, you have the ability to make an
appropriate constructor for ints, remove the explicit keyword, or convert the int to a
float yourself. |
|
const |
Use this liberally. Anywhere you notice a function changes nothing in a class, add const to the end of the function declaration before the semicolon. Anywhere you notice a parameter not being changed in a function, change the parameter declaration to const type name. The more often you use const in the right places, the more often you get the satisfaction of fixing code which was unsafe. Try not to cast away this property ever. See mutable. |
|
Dynamic_cast<type>(var) |
This casting type is special.
It only works with Run Time Type Information (RTTI) enabled. This allows you to attempt to
cast from one type to another and be certain of the answer. Dynamic_cast<>()
will return NULL if the variable is not of the cast type. Otherwise, it will return that
same pointer, but as a pointer to the destination type. This is helpful when trying to
figure out what kind of object you have in a large list of base objects, and theres
no simple way to find the answer. RTTI does increase memory and some CPU load, but
its supposedly minimal. Ive used this once or twice and thought it was neat.
You cant make a switch statement of these, however. Use this when it seems
appropriate and you can afford RTTI. |
|
Mutable |
Const_cast<>() |
Mutable is a variable
declaration modifier. If you absolutely need to change a variable from within a function
you declared const, and you are certain your interface is not broken in some way, declare
that member variable as mutable and itll compile and work. Note that if you use this
a lot, having a const function loses meaning. I have used mutable mostly to change boolean
flag values or to reset variables which would be a performance hit to do elsewhere.
Sometimes when you combine two functions into one and still want to keep it as a const, so
you dont have to const_cast all over your code, this can save you hours of
search-and-replace. |
Single Inheritance |
Multiple Inheritance |
Some people feel strongly that
multiple inheritance is the only way to build powerful code. I feel strongly that
its the only way to build code which is difficult to understand, debug, and
maintain. It has serious performance issues on at least three major compilers, and most
likely will never be as good as single inheritance designs. If you dont care about
performance, you might consider single inheritance anyway, just to see how it can be done.
It may lend a new perspective. |
Protected: |
Public: |
There are very very rare exceptions where a class has public variables. In almost every case, we write a simple inline function which will get or set the variable if it is necessary at all. Youll find that public variables makes it a real pain to change the implementation of a class, and particularly hard to track down where flags and booleans are being set if theres no funneling routine where you can smack down a breakpoint. |
As long as there are templates, there will be code bloat and instantiations of
templated classes that won't work because not all types were tested against the template.
That's a fact. However, they can be used very effectively to wrap ADTs and
algorithms which operate on unknown types without losing type safety, which is a very big
win for code safety. A good rule of thumb is, template code should not be
distributed to others as 'library code'. It's just unlikely that you've tested all
your permutations and could be months or years before someone realizes how broken it is in
just this one case they care about.
Another big one is constructors. Do you look at your classes as C programmers look
at structs? You do if you usually have a default constructor defined. "Fancy
C" is the term used to describe programmers who are using C++ to be a little
lazier, without making their coding practices much less error prone. For example, a
struct is transparent because a user always has access to its members. A class, if
written correctly, does not allow access or even the idea of how the implementation works
for an interface. What, then, is the difference between a default constructor and a
number of Setsuchandsuch methods, and a struct? Guaranteed
initialization! you say. Sure. I guess, if that's all you want.
The keys are in your hand, but you haven't bothered to fit them to the door yet.
What you want is Guaranteed construction.
Guaranteed initialization means your object, from declaration, has no unknown values
inside its members. Essentially, your constructor fills your struct will zero (or an
appropriate default value), and you expect the user to call the right methods to fill it
out before using it. "Before using it". Did you catch
that? That means your user has the ability to declare objects that you
provided which cannot be used until certain hoops have been jumped through. Even if
you put in assertions in every function call to make sure that all those steps have been
taken, a user will not find out that their code is faulty until execution of that code.
Bad. Very bad. Why not catch it at the compile step? Why not make
it so that they cannot even create the object without it being a fully usable, fully
constructed object?
Guaranteed construction means your object cannot be constructed in such a way that it is
unusable immediately. This may mean that you don't define a default constructor
because a default value is meaningless for your object. Take a Vector for example.
A Vector(0,0,0) constructor call could be identical to Vector() constructor call,
if you define a default constructor. The problem is, someone could decide later that
a Vector() should really be equivalent to Vector(1,0,0). All the code that depends
on the default constructor is broken, and is incredibly painful and slow to fix.
Take another example, a Date class, which understands time and can spit back out
Gregorian or Julian dates. If the Date class constructs with no parameters, it can
only assume you mean current time, right? Why not assume you meant to pass in time
0, which would be in either Gregorian or Julian time? There's no smart way to define
that constructor, so don't. Always require a Date to construct by explicitly causing
the user of the class to construct it with a time or another Date. It's a ton safer
that way, and you never have to worry about someone asking a dumb question about how to
set up an object before using it.
Note, there are two problematic exceptions to this approach:
First, you cannot have an array of objects which do not define a
default constructor. Can't do it. This means you need to learn how to use
container classes, like those provided in the Standard Template Library (STL). Yes,
there are problems with the STL, but many of them can be solved with some perseverence.
Second, container objects are 'legal' to have default constructors,
usually. These objects are specifically designed for the containment of other
objects. For example, if you created a List class, you might give it a default
constructor because you could legitimately want a List with no elements. An empty
List is a valid construct.
Put these two restrictions together and you have the makings of a new way to write code in
C++. Notice that because your member variables all have non-default constructors
that you are required to set them up in the initializer lists of your class constructors?
This means you have to pass in enough information to fully create the elements of a
class in that class' constructor, or you can't write the constructor. This often
points out mistakes in class hierarchy design. If you can't construct something in
one go, you probably don't need it yet. Create the bits and pieces that make it up,
then construct your object later, once the parts are all present. This mentality
prevents you from creating an object partially constructed, even though it takes a little
getting used to the idea that you can't use multiphasic construction through Setthisandthat
calls. Let it go. It isn't worth it.
There is something called the Not Invented Here Syndrome. Most programmers and managers feel it is important to build and maintain their own tools and libraries so they can totally control the developmental path of the work. As much as this is reasonable, there are times when doing so is unreasonableparticularly when a package has been made publicly available and has been debugged and tested for many years, and would suit your purposes extremely well. Sometimes these packages have not been considered out of ignorance of their applications, their strengths, or an interest to reinvent the wheel. I'm not going to be able to list every package freely available, but I will suggest some sites to look over and explicitly mention some packages I've used in my own code.
Some sites to look over:
Virtually Unix
Gnu's Home Page
List of Gnu ftp sites
Lex (Flex)
Lex is a lexical analyzer-maker. It outputs .c code which you compile into your project based on a series of rules you write to control it. It reads in a file (or files) and will deal with what it reads according to rules you write. It is based on Regular Expression syntax, which is fairly common and standard among unix utilities, but has a quirk or two for certain versions of Lex. For each rule that is triggered, a snippet of code that you write is executed. This gives you total control over the most minute details of the data that you are reading. Lex is most often used as a front end to Yacc for complex jobs, however. Lex is very suitable for building simple applications which do word counting, testing for certain types of input, or basically any kind of scanning without too much emphasis placed on data order.
Flex distribution
Yacc (Bison)
Yacc is a parser-maker. Again, you write rules to control
how the grammar of the data must conform, and Yacc will spit out some .c code which will
do that for you. The Lex and Yacc rules are the basis of many languages and compilers.
Together, they make very powerful tools which can create complex data from human-readable
input. Human data is hard to interpret and check over for mistakes and turn into useful
output, and Lex and Yacc allow you to do that with minimal effort. I'll caution you that
it may take a week or two for someone who has never seen or used either of these to really
get the concepts and feel 100% comfortable working with them. For reference, that's how
long it took me to get accustomed to them. Now I want to do everything involving text
input with them.
Bison distribution
Gnu C++ preprocessor (cccp)
The intricacies of preprocessing a set of header files or source code files are rather complex. As much as you might feel the urge to write your own, dont. Once youre finished, I can point you to a chapter of the C++ Annotated Reference Manual by Stroustrup which will shoot holes in your preprocessors feature set and probably leave you feeling pretty annoyed that you wasted so much time on it. I found that Gnus gcc library contains the source code to their preprocessor, which is particularly featureful and easy to use. Within an hour, I'd converted it from unix to pc, removed the command line interface and replaced it with a very simple filename parameter and had it in place of my own preprocessor, doing everything right and as you'd expect, instead of mostly right and like you'd expect but not quite. By supporting typical #define, #include, and specializing your own #pragma directives, you can very easily make the exact same header and include files you compile with be read by your data.
GCC distribution
from which you want cccp.c and related files.Zip Format Source
What can I say? Zip is really useful, particularly when you need to interface with Java or you would like to use a well-debugged compression library as your data file format. You can find a .tar.gz of the Zip source code archive at the Info-Zip home page.
JPEG Format Source
JPEG is the most common and best compressed graphic format
available for still pictures today. Most people want to support it if they do any sort of
graphic manipulation in their app. You can get very straightforward MSVC++ 4.x/5.0 source
code to do it at Smaller
Animals Software.
Or you can get the publicly release code from the International JPEG
Group.
TIFF Format Source
TIFF is a very complex, very capable format which can
accommodate nearly any lossless graphic formats needs. Once you have JPEG and TIFF
loaders, you can basically write or find source for anything else, or find a converter
from other formats into these. Unfortunately, TIFF is at revision 6.0 and there is no
public code to read the new 6.0 extensions, which incidentally have been proclaimed a
disaster anyway and an even newer spec has been devised. It has something to do with
integrating JPEG images into the TIFF format poorly. The public TIFF 5.0 source code is
available on the Silicon
Graphics ftp site.
PNG Format Source
PNG is the newest format from the people who created the
JPEG standard, I think. They're making a totally portable, fully featured format which has
no legal issues with its compression, unlike LZW used in the GIF format. My suggestion is
to move away from GIF and other LZW-based formats, unless you like paying thousands of
dollars to Unisys for licensing. The public PNG source code is available on the PNG home page.
ZLib Compression Library and Source
ZLib is the backbone of PNG and plenty of other new apps
which depend on fast, portable compression algorithms. I haven't looked into this too
extensively, but I imagine it could be integrated into an existing codebase with a good
interface class with little trouble. You can find it through the PNG page above, or go
straight there by clicking here.