Cyclic Dependencies: Clean the Up!

September 14th, 2008

Cyclic dependencies are a challenge for any build system and code to handle. But I you look closely at cyclic dependencies, in most if not all cases they are a structural problem and not a technical problem. Cyclic dependencies indicate in most cases either that two modules belong together or one module implements two tasks.

Let’s take a projcect I am currently working on. There are two modules, the Interpester and the Object Manager, both are cyclic dependent. The Interpreter implements a virtual machine. The Object Manager implementes object serialisation and low level buissness logic. The basic contollflow is as follows: Object Manager calls Interpreter to evaluate some value and to do this the Interpreter calls back into the Object Manager get values to a given object.

If you read the above paragraph cloasly you will notice that the Object Manager implements “object serialisation and low level buissness logic”. Well as you can see there are two tasks that can and should be split in two seperate modules. If they are split in three modules there are no cyclic denendencies.

The Beauty of C++ Cast Operators

April 19th, 2008

Many criticize the C++ explicit cast operators. Common points of critique is that they are clumsy or redundant. But I believe that most people who are criticizing the cast operators did not understand what the point is about them.

A Bit of Theory

If you do not know what I am talking about, the explicit cast operators are static_cast, reinterpret_cast, dynamic_cast and const_cast. Every cast operator has its own use, lets see what it is.

The const_cast operator is there to add or remove const or volatile. It is not often used, but some cases where you are working with “broken” third party libraries, this operator can be required.

The dynamic_cast is used then casting polymorphic objects. It is a safe cast since it only returns a useful result when the cast is successful. This is done with the help of runtime type checking and can give a slight performance hit.

The reinterpret_cast is used when you blindly want to map the bit pattern from one type into the other. This was never possible with C casts.

The static_cast is the simplest cast there is. It is almost the analogue to the C cast, except for removing or adding const or volatile. It can do the same things as dynamic_cast only the safety disabled.

Casts are Evil

Although this bold statement is slightly exaggerated, if you have casts in your code there is a good chance that there is a flaw in your design. Casts mean that you convert from one type into the other, why is the data not the the format you need it?

It is true that you need casts when you connect two pieces of software together, such as adding some third party software to yours. But even here the requirement to convert from one format to the other is a flaw, even though it might be only a minor flaw.

Every time you cast data can be lost or potentially turn out to nonsense. The new cast operators make the cast clearly visible and debugging often becomes easier, since potential places of data loss are clearly marked.

Not Really Awkward

The cast operator look like functions and if you really think about it they are not as awkward as C casts. In addition concepts such as lexical_cast or any_cast where easily accepted the syntax closely follows the “real” C++ casts.

If you ever accessed a member with a C cast, compare the two alternatives:

// C cast
((MyType*)value)->some_member;

// C++ cast
dynamic_cast<MyType*>(value)->some_member;

Not that this code is good style, since the cast may fail. But the C++ cast does not need any odd parentheses and you can’t cast the result by mistake.

std::tstring

February 18th, 2008

If you are using Microsoft Visual Studio the use of the Microsoft Foundation Clases (MFC) is often seen as a must. But MFC is a relative large library and many modules don’t use much of it. There are cases where the only piece of MFC is CString. But linking against MFC just for CString is superfluous.

Since the standard C++ library is always bundled with every compiled program the use of std::string and std::wstring is a good alternative. Conversion from and to CString is trivial, if you know the current settings.

The problem is that many functions defined by the WinAPI and MFC are dependent if Unicode is used or not. Depending on the settings either char or wchar_t us used. So code is independent to this setting TCHAR can be used. It will then be defined to the one or the other.

In the one case you can plainly convert to std::string in the other std::wstring. But which do you use in your code. This gets worse if you receive and return the strings; character set conversion is out of the question.

The Microsoft Solution

If you read about this in the Microsoft Developer Network (MSDN) you get a plain solution: Use the preprocessor.

#ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif

This solution follows the same as many proposed by Microsoft. But if you give me a Euro for every #undef I needed to write in my code, bacause a macro from the WinAPI tainted my code, I would be rich.

Definition

Since we are programming C++, it is wise to solve the problem with the means of the language instead of the using a preprocessor hack. The definition of tstring follows the definition of string and wstring. tstring is a variant of the template basic_string with TCHAR. To add a little type safety and portability I defined tchar_t following the idea of wchar_t.

namespace std
{
    typedef TCHAR tchar_t;
    typedef basic_string<tchar_t> tstring;
}

tchar_t and tstring where defined in the namespace std, to show that it actually just is a special form of basic_string and fully compatible to other standard code.

Streams

Well now that you have your string class dependent on TCHAR, there is the problem of streams. Streams are also parameterized for char or wchar_t. But here the solution is straight forward. Define your own types based on ”basic_streamtype”

namespace std
{
    typedef basic_ios<tchar_t>              tios;
    typedef basic_streambuf<tchar_t>        tstreambuf;
    typedef basic_istream<tchar_t>          tistream;
    typedef basic_ostream<tchar_t>          tostream;
    typedef basic_iostream<tchar_t>         tiostream;
    typedef basic_stringbuf<tchar_t>        tstringbuf;
    typedef basic_istringstream<tchar_t>    tistringstream;
    typedef basic_ostringstream<tchar_t>    tostringstream;
    typedef basic_stringstream<tchar_t>     tstringstream;
    typedef basic_filebuf<tchar_t>          tfilebuf;
    typedef basic_ifstream<tchar_t>         tifstream;
    typedef basic_ofstream<tchar_t>         tofstream;
    typedef basic_fstream<tchar_t>          tfstream;
}

Conversion To and From CString

Conversion to and from CString, LPTCSTR or LPTSTR is plain simple. The most important aspect is that no character conversion is necessary.

Conversion from CString to std::tstring:

CString     cstr(_T("test"));
std::string std_str(cstr);

Conversion from std::tstring to CString:

std::string std_str(_T("test"));
CString     cstr(std_str.c_str());

Conclusion

Just because other modules use TCHAR, LPTSTR, LPTCSTR or CString does not mean you can’t use C++ standard classes. You only have to create your own variants.