.bat file continuation character
Friday, May 26, 2006
I've finally found the continuation character for continuing a line in a bat file. It is the caret "^".
Labels: General
posted by tac @ 6:24 PM, , links to this post
New mailing list added to notify readers of new posts
Tuesday, May 16, 2006
I just added a new mailing list for those people who wish to be updated when a contributor posts a new discussion topic. If you wish to be added to this mailing list (GilemonsterBlog@googlegroups.com), send me an email along with your email address and I'll add you to the group.
-Gilemonster
Labels: Site News
posted by Gilemonster @ 6:18 PM, , links to this post
Should architects code?
This is always an interesting discussion to me (since I am an architect). I just saw this article on this topic in Dr. Dobb's.
Personally, I think architects should be keep their fingers in the code to some extent. I just think it's difficult to architect/design a system if you don't know how it will be built. I don't write as much code as I used to, but I still like to stay involved and even participate in some coding and detailed design exercises from time to time.
Labels: General
posted by TigerEagle @ 3:31 PM, , links to this post
Discussion Topic #2: Create standalone and "guarded" header files
Monday, May 15, 2006
When writing C++ header files, you should always be conscious that your header files can be included by other projects and files. The reason for doing this is because improperly written header files can cause a number of problems including stray dependencies, unnecessary include burdens on your header file's users, and multiple inclusion/redefinitions to name a few. Two techniques that help to prevent this are making your header files standalone and using include guards. Both techniques are described below.
Make Your Headers Self-SufficientHeader files should be written so that they can stand on their own two feet. Header files that include other unneeded header files can cause stray dependencies and longer build times (because the compiler is required to parse each header file that is included at compile time). The first step in making your header files self-sufficient is to look at each header file it includes and then verify that it actually needs to include that file. This is easily verifiable by just commenting out the included file and then recompiling. If the compile fails, at least that included object's type is needed. If the compile works, you can delete the commented out include altogether. Once you have verified which includes are required, the second step is determine what objects in those header files are actually needed. If you do not need the included object's definition (i.e. You return it from a function, it is declared as a parameter in one of your functions, etc) you can forgo including the type's definition in your header. You can achieve this with a forward declaration. A forward declaration allows you to declare the use of a type without the details of its definition. Note: The only time you need the type's definition in your header is when the compiler needs to know the size of the type (i.e. your have the included object as a member of your class) or when you need to use/call a member of that type (i.e. you invoke a function on the included object). Here is a sample header that shows displays forward declares and also minimal include directives:
#include <atlbase.h> // include header for VARIANT class member class SnmpRequestResults; // forward declaration of results class class SnmpRequest { public: SnmpRequest(); ~SnmpRequest(); SnmpRequestResults* GetResults(); private: VARIANT m_vDataType; };
As you can see in the above SnmpRequest class, we use both the forward declaration and a small number of include directives (we only include atlbase.h). We have removed the need for including the SnmpRequestResults header in our header and therefore made our own header file more self-sufficient. When using these techniques, think of your header files as being used completely by itself.
Use #include GuardsMake sure that your header files are only defined once in case it is included multiple times. You can guarantee this with the use of include guards. Modern compilers recognize these guards at the top of header files and therefore prevent multiple inclusions of a header file during the compilation of a single cpp file. They are implemented with preprocessor directives. The guards need to conform to the following rules:
- The name needs to be unique.
- No code or comments should come before or after the guarded portion.
- The guards should wrap the entire object declaration.
Here is an example of include guard use:
#ifndef FOO_H_INCLUDED #define FOO_H_INCLUDED class Foo { public: Foo(); ~Foo(); int ComputeFooSize(); }; #endif
By using include guards and making header files self-sufficient, you can make your header files lightweight and therefore easier to use by other code. It also has the indirect affect of you having to write less code. That's always good. I hope this was helpful and if there are any questions, post away.
- Gilemonster
Labels: C++
posted by Gilemonster @ 8:48 PM, , links to this post
Visual Studio Code Analysis Tools?
Friday, May 12, 2006
Has anyone used the new code analysis tools builtin to Visusal C++ 2005? What do you think about the features? Do the tools find relevant bugs?
posted by TigerEagle @ 10:36 AM, , links to this post
Discussion Topic #1: Logical vs. Bitwise constness
Sunday, May 07, 2006
One of my favorite C++ programming tips is the use of const as a semantic constraint. I use it whenever and wherever I can because it can significantly reduce logic errors and turn them into compile errors (a good thing). In order to use it properly, you need to know how C++ defines constness. There are two types of object constness in the C++ world and they affect class design in different ways.
C++ compilers, by default, support the use of bitwise constness. This means that no part of an object can be modified after instantiation when declared with the const modifier. Inside a class definition, this is great for "getter" functions that merely return values to the caller. By declaring the functions const, you are telling the caller (and the compiler) that this member function cannot modify any members of the class it is working on. Here's an example:
class MyObject { public: MyObject(); // constructor ~MyObject(); // destructor long GetObjectID() const; void SetObjectID(long lngID); long GetObjectLength() const; void SetObjectLength(long lngLength); private: long m_lngID; long m_lngLength; };
In the above example, you will notice that there are two class functions that are defined with the const modifier. This tells the compiler that the function will not modify either the m_lngID or m_lngLength class members. So, by default, the definitions of the two "get" functions above cannot contain code that changes those two private class members. Here's a sample function definition:
long MyObject::GetObjectID() const { m_lngID = 25; // ERROR! m_lngLength = 0; // ERROR! return m_lngID; // Allowed! }
Above you will note that attempts to assign values to m_lngID and m_lngLength will cause the compiler to generate an error. Alternatively, the return statement will not generate an error b/c it is merely returning a copy of one of the class' data members. Its not changing it.
Now sometimes you need a const function that guarantees it won't change certain class members, but might change others. This brings about the idea of logical constness. Let's say you have a class member who's value can be changed (and that not affect your object's definition of constness). In C++ you can declare this member with the keyword mutable. This can be useful at times. Scott Meyers suggests that when designing interfaces, you should use logical constness. He makes a good point b/c mutable gives the designer the ability to create his/her own definition of what constness means for a particular object. Example below:
class MyObject { public: MyObject(); // constructor ~MyObject(); // destructor long GetObjectID() const; void SetObjectID(long lngID); long GetObjectLength() const; void SetObjectLength(long lngLength); private: mutable long m_lngID; long m_lngLength; };
The above class mirrors our earlier example in all aspects except that the m_lngID member is declared with the mutable modifier. This tells the compiler to allow modifications to this member inside of const class functions. Here's a sample function definition:
long MyObject::GetObjectID() const { m_lngID = 25; // Allowed b/c the member mutable m_lngLength = 0; // ERROR! return m_lngID; // Allowed! }
The above function definition shows how the compiler will treat both member variables based on whether they where declared using mutable.
So, from the examples above you can see how using const as a semantic constraint can be useful. The examples above also show how mutable allows the designer to define what constness means for a particular object. There is one final note to this topic and that is const modifiers aren't "full-proof" in their protection of class member modification. Let's add a new routine to our MyObject class that returns a pointer to a character string:
class MyObject { public: // Constructor, destructor, blah blah... char * GetObjectName() const; private: char * m_strObjectName; }; // Defintion char * MyObject::GetObjectName() const { return m_strObjectName; }
The GetObjectName() function is declared as a const function, but the private m_strObjectName variable isn't safe from modification! How can that be you say? The reason is because the function is returning a pointer to the class' data member. Anyone can now take that pointer and do with it what they wish. Here's the correct way to declare the above routine and ensure the name variable isn't changed:
const char * GetObjectName() const;
This states that we aren't going to change m_strObjectName in the function and also that we are returning a pointer to a constant character string. The string that the pointer "points" to cannot be changed. This now guarantees that the caller can only query the value of the class' name member.
I hope this wasn't too confusing. If so, let me know and I'll attempt to further demonstrates the idea. The bottom line is that using const forces code semantics that improve code stability. Understanding how C++ defines constness also allows the designer to provide more customized object definitions.
- Gilemonster
Labels: C++
posted by Gilemonster @ 11:44 AM, , links to this post
Recommended C++/STL Reading
Thursday, May 04, 2006
I've read a number of articles/books on general C++ programming and have created my own personal list of books that are a requirement in your own cube. It is my opinion that anything Scott Meyers writes is worth reading. They are always informative and interesting.
- Effective C++ (3rd ed.)
- More Effective C++
- Effective STL
They are great to keep around if you are like me and can't remember all the topics you've read in the past. Others?
-Gilemonster
Labels: C++
posted by Gilemonster @ 10:47 PM, , links to this post