Two days ago I posted a simple implementation of a game of colors. Though it was intended only as an exercise, someone has criticizes the use of an int** to hold the grid information, mainly for two reasons:

  • the footprint on 64-bit platforms can get nasty
  • the explicitly allocated memory, instead of using a std::vector

So this is the code:

int** m_pCells; 

void Create()
{
   m_pCells = new int*[m_nSize];
   for(int i = 0; i < m_nSize; ++i)
      m_pCells[i] = new int[m_nSize];
}

Let's see how much memory it takes. The total size should be:

totalsize = sizeof(m_pCells) + sizeof(m_pCells[0]) * m_nSize + m_nSize * m_nSize * sizeof(int);

On 32-bit platforms, the size of a pointer is the same with the size of int and is 4 bytes. For the maximum size allowed for my grid, which is 50, the total size in bytes for the grid is: 4 + 4*50 + 50*50*4 = 10204.

On 64-bit platforms, the size of a pointer is 8 bytes, but the size of int is still 4 bytes. So for a grid with 50 rows and columns it needs: 8 + 8*50 + 50*50*4 = 10408 bytes. That's a 2% increase of required memory.

The memory footprint was the last thing I had in mind when I wrote this simple exercise. Well, of course there is a way to require only 4 more bytes on 64-bit platforms. And that is using an int* allocating m_nSize*m_nSize elements.

int* m_pCells;

void Create()
{
   m_pCells = new int[m_nSize * m_nSize];
}

void Destroy()
{
   delete [] m_pCells;
   m_pCells = NULL;
}

With this implementation, when you need to access the element at row i and column j, you have to use m_pCells[i * m_nSize + j].

As for the second argument, that explicitly using operator new[] to allocate memory instead of using a vector of vectors, well, what could I say? Sure, why not. Different people use different programming styles. As long as all implementation are correct and achieve the same goal with similar performance, I guess everyone is entitle to code as he/she wants. But if we go back to the memory footprint, I would also guess that the use of vectors would take more memory than pointers to int, because the size of a vector is several times the size of a pointer. But I wouldn't say that's an important issue here.

Anyway, these arguments remember me the joke (or maybe it's serious) about the rules of optimization:

  1. Don't optimize.
  2. Don't optimize yet (for experts only).

(Of course there are super experts that can ignore these rules.)

, , , , Hits for this post: 492 .

Some of the important changs in Visual Studio 2010 in regard to VC++ are represented by the support in the C++ compiler of some of the features already approved for the new C++ standard, so far called C++0x. In this post I will give a short overview on then.

static_assert

I already wrote a post about this feature. At that time I considered it rather a niche feature. However, this looks much powerful in conjunction with the type traits classes from TR1.

static_assert checks if an expression is true at compile time. If the expression if false a custom error message is displayed and the compilation fails. If the expression is true the declaration has no effect.

In the following example I create a comparison template function, that is used later to compare values.

template < typename T >
bool CompareNumbers(T v1, T v2)
{
   return v1 > v2;
}

int main()
{
   bool ret1 = CompareNumbers(1, 20);
   bool ret2 = CompareNumbers("b", "a");

   return 0;
}

I want this function to be used only for integral types (the reason doesn’t matter) and I’d like the compiler to issue an error when used with any other type. Adding a static_assert check will generate a compilation error for the second call to the function, when passing strings.

#include < type_traits >

template < typename T >
bool CompareNumbers(T v1, T v2)
{
   static_assert(std::tr1::is_integral< T >::value, "Type is not numeric");
   return v1 > v2;
}
1>d:\marius\vc++\cpp0x\cpp0x.cpp(62): error C2338: Type is not numeric
1>          d:\marius\vc++\trainnings\cpp0x\cpp0x.cpp(75) : see reference to function template instantiation 'bool CompareNumbers(T,T)' being compiled
1>          with
1>          [
1>              T=const char *
1>          ]

auto

If you are familiar with C#, this is the C++ equivalent of var. The keyword is used to deduce the type of a declared variable from its initialization expression. The initialization expression can be an assignment, direct initialization or operator new expression. It must be noted that the auto keyword is just a placeholder, not a type, and cannot be used with sizeof or typeid.

auto i = 13;        // i is int
auto s = "marius";  // s is std::string
auto p = new foo(); // p is foo*

vector< int > numbers;
generate_n(back_inserter(numbers), 10, rand);
for(auto it = numbers.begin(); it != numbers.end(); ++it)
{
   cout << *it << endl;
}

lambda expressions

I already wrote about lambdas, but I will give a short overview again. Again, if you are familiar with C# and .NET, this is the same concept as in .NET.

A lambda functions is a function object whose type is implementation dependent; its type name is only available to the compiler. The lambda expression is composed of several parts:

  • lambda_introducer: this is the part that tells the compiler a lambda function is following. Inside the angled brackets a capture-list can be provided; this is used for capturing variables from the scope in which the lambda is created.
  • lambda-parameter-declaration: used for specifying the parameters of the lambda function.
  • lambda-return-type-clause: used for indicating the type returned by the lambda function. This is optional, because most of the time the compiler can infer the type. There are cases when this is not possible and then the type must be specified. For the example above, the return type (-> bool) is not necessary.
  • compound-statement: this is the body of the lambda.
vector< int > numbers;
generate_n(back_inserter(numbers), 10, rand);

for_each(numbers.begin(), numbers.end(), [](int n) {cout << n << endl;});

Here [] is the lambda introducer, (int n) is the lambda parameter declaration, and {cout << n << endl;} is the lambda compound statement. There is no return type clause, because that is auto inferred by the compiler. There are cases when the compiler cannot deduce the return value and then it must be specified explicitly. A lambda expression is a syntactic shortcut for a functor. The code above is equivalent to:

class functor_lambda
{
public:
   void operator()(int n) const
   {
      cout << n << endl;
   }
};

vector< int > numbers;
generate_n(back_inserter(numbers), 10, rand);

for_each(numbers.begin(), numbers.end(), functor_lambda());

Lambdas can capture variables from their scope by value, reference or both in any combination. In the example above, there was no value captured. This is a stateless lambda. On the other hand, a lambda that captures variables is said to have a state.

rvalue references

Stephan T. Lavavej wrote the ultimate guide to rvalue references. There is nothing more that can be said that is not already there. I strongly suggest you read his article to familiarize with this concept.

rvalue references are used to hold a reference to a rvalue or lvalue expression, and are introduced with &&. They enable the implementation of move semantics and perfect forwarding.

Move semantics enable transferring resources from one temporary object to another. This is possible because temporary objects (i.e. rvalues) are not referred anywhere else outside the expression in which they live. To implement move semantics you have to provide a move constructor and optionally a move assignment operator. The Standard Template Library was changed to take advantage of this feature. A classic example for the move semantics is represented by operation with sequences like vector or list. A vector allocates memory for a given number of objects. You can add elements to it and no re-allocation is done until the full capacity is reached. But when that happens, the vector has to reallocate memory. In this case it allocates a new larger chunk, copies all the existing content, and then releases the pervious memory. When an insertion operation needs to copy one element several things happen: a new element is created, its copy constructor is called, and then the old element is destroyed. With moves semantics, the allocation of a new element and its copy is no longer necessary, the existing element can be directly moved.

A second scenario where rvalue references are helpful is the perfect forwarding. The forwarding problem occurs when a generic function takes references as parameters and then needs to forward these parameters to another function. If a generic function takes a parameter of type const T& and needs to call a function that takes T&, it can't do that. So you need an overloaded generic function. What rvalue references enable is having one single generic function that takes arbitrary arguments and then forwards them to another function.

decltype operator

This is used to yield the type of an expression. Its primary purpose is for generic programming, in conjunction with auto, for return types of generic functions where the type depends on the arguments of the function. Here are several examples:

double d = 42.0;     // decltype(i) yields double
const int&& f();     // decltype(f()) yields const int&&
struct foo {int i;}; // decltype(f.i) yields int (f being an object of type foo)

It can be used together with auto to declare late specified return type, with the alternative function declaration syntax, which is (terms in squared brackets indicate optional parts)

auto function_name([parameters]) [const] [volatile] -> decltype(expression) [throw] {function_body};

In general, the expression use with decltype here should match the expression used in the return statement.

struct Liters
{
   double value;
   explicit Liters(double val):value(val){}
};

struct Gallons
{
   double value;
   explicit Gallons(double val):value(val){}
};

ostream& operator<<(ostream& os, const Liters& l)
{
   os << l.value << "l";
   return os;
}

ostream& operator<<(ostream& os, const Gallons& g)
{
   os << g.value << "gal";
   return os;
}

Liters operator+(const Liters& l1, const Liters& l2)
{
   return Liters(l1.value + l2.value);
}

Gallons operator+(const Gallons& g1, const Gallons& g2)
{
   return Gallons(g1.value + g2.value);
}

Liters operator+(const Liters& l, const Gallons& g)
{
   return Liters(l.value + g.value*3.785);
}

Gallons operator+(const Gallons& g, const Liters& l)
{
   return Gallons(g.value + l.value*0.264);
}

template < typename T1, typename T2 >
auto Plus(T1&& v1, T2&& v2) -> decltype(forward< T1 >(v1) + forward< T2 >(v2))
{
   return forward< T1 >(v1) + forward< T2 >(v2);
}

int main()
{
   cout << Plus(l1, l2) << endl;
   cout << Plus(g1, g2) << endl;
   cout << Plus(l1, g1) << endl;
   cout << Plus(g2, l2) << endl;

   return 0;
}

The result of the execution is:

15l
30gal
42.85l
22.64gal

When function Plus is called with arguments of the same type, the result is that type. But when the arguments differ, the resulting type is also different. In this example, when the first argument is Liters and second is Gallons, the result type must be Liters and the opposite. It is possible to do this without decltype, but the solution requires explicit specification of the resulting type.

template < typename T, typename T1, typename T2 >
T Plus(T1&& v1, T2&& v2)
{
   return forward< T1 >(v1) + forward< T2 >(v2);
}

int main()
{
   cout << Plus(l1, l2) << endl;
   cout << Plus(g1, g2) << endl;
   cout << Plus(l1, g1) << endl;
   cout << Plus(g2, l2) << endl;

   return 0;
}
, , , , , Hits for this post: 5794 .

I recently found a piece of code that can be summarized by the following sample:

interface I
{
   void F1();
   void F2();
}

class X
{
   public void F2() { Console.WriteLine("F2"); }
}

class A : X, I
{
   public void F1() { Console.WriteLine("F1"); }
}

As you can see there is an interface I that has two methods, F1 and F2. A is derived from X, that has a method F2, and also implements I, but only contains F1. I was puzzled at first, because I was expecting that A was explictitly implementing all the methods defined in the interface I. But F2 was implemented in X, its base class. After thinking a little bit it all become clear. This was a normal behavior of the compiler.

When a class A implements an interface I it guarantees that it supports (implements) the entire contract that the interface defines. But it does not assert that it will explicitly implement all the interface members within its explicit definition. I’m stressing on the explicit word here, because A extends (is derived from) X. That means A is an X. Everything that X exposes (i.e. what is visible to its derived classes) is part of A too.

In our case, F2, implemented in X, is also available to A, because A is an X. Since both F1 and F2 are members of A, then it means A fully implements I, which makes the code compile just fine.

How is this helpful? Suppose you have several interfaces that all define one ore several members with the same meaning.

interface I1
{
  void F1();
  void F2();
  int ErrorCode { get; }
}

interface I2
{
  void G1();
  void G2();
  int ErrorCode { get; }
}

interface I3
{
  void H1();
  int ErrorCode { get; }
}

Instead of providing the same implementation several times, like in the following code, you can have only one implementation for the common functionality.

class A : I1
{
  private int m_errorCode;

  public void F1() {}
  public void F2() {}
  public int ErrorCode { get {return m_errorCode;} }
}

class B : I2
{
  private int m_errorCode;

  public void G1() {}
  public void G2() {}
  public int ErrorCode { get {return m_errorCode;} }
}

class C : I3
{
  private int m_errorCode;

  public void H1() {}
  public int ErrorCode { get {return m_errorCode;} }
}

We can create one class that provides the implementation for ErrorCode and let the others extend it and implement the corresponding interface.

class X
{
  protected int m_errorCode;

  public int ErrorCode { get {return m_errorCode;} }
}

class A : X, I1
{
  public void F1() {}
  public void F2() {}
}

class B : X, I2
{
  public void G1() {}
  public void G2() {}
}

class C : X, I3
{
  public void H1() {}
}

, , , Hits for this post: 4724 .

.NET provides two classes for image transformations: Matrix, used for geometric transformations, and ColorMatrix, used for color transformations.

One of such color transformations is inverting or negating. This means subtracting each color component from 255. Black (0,0,0) becomes White (255, 255, 255), and Green (0, 255, 0) becomes Magenta (255, 0, 255).

You can find many examples on the web that look like this:

public Bitmap Transform(Bitmap source)
{
    //create a blank bitmap the same size as original
    Bitmap newBitmap = new Bitmap(source.Width, source.Height);

    //get a graphics object from the new image
    Graphics g = Graphics.FromImage(newBitmap);

    // create the negative color matrix
    ColorMatrix colorMatrix = new ColorMatrix();
    colorMatrix.Matrix00 = colorMatrix.Matrix11 = colorMatrix.Matrix22 = -1f;
    colorMatrix.Matrix33 = colorMatrix.Matrix44 = 1f;

    // create some image attributes
    ImageAttributes attributes = new ImageAttributes();

    attributes.SetColorMatrix(colorMatrix);

    g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
                0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);

    //dispose the Graphics object
    g.Dispose();

    return newBitmap;
}

Using this code one can get a negative image.

Original image

Original image

Negative image

Negative image

This runs fine on Windows XP. But when I ran it on Windows 7, I was getting only a black image. All the pixels were ARGB(255, 0, 0, 0). This was how it looked:

Incorrectly transformed image

Incorrectly transformed image

I was surprised to learn that it worked on Windows XP, but not on Windows 7. I don’t have Windows Vista to test but I guess it’s the same as with Windows 7. I thought it must be something in the GDI+ library, because building with .NET 3.5 SP1 or 4.0 Beta 2 didn’t change a thing.

After trying different things, I figured out what the problem was: the color matrix was incorrect. It must be defined like this:

ColorMatrix colorMatrix = new ColorMatrix(
   new float[][]
   {
      new float[] {-1, 0, 0, 0, 0},
      new float[] {0, -1, 0, 0, 0},
      new float[] {0, 0, -1, 0, 0},
      new float[] {0, 0, 0, 1, 0},
      new float[] {1, 1, 1, 0, 1}
   });

With this change the Transform function produces a correct negative image, regardless the operating system or the .NET framework version.

However, what I don’t know yet, is why it worked on Windows XP. The only conclusion I can draw is that the GDI+ implementation has a fault there, that was later corrected. That’s why an incorrect color matrix produced a correct transformation on Windows XP.

, , , , Hits for this post: 4940 .

Sometimes you want to customize a file dialog, maybe to provide a preview for images or files in general. Fortunately, the common file dialog can be easily extended to achieve this. I will explain in this post how to do that.

There are several things one needs to do to extend the file dialog. First step is to create a dialog template. There are several properties (styles that have to be set on this template).

  • WS_CHILD, necessary because this dialog is a child of the original file dialog
  • WS_CLIPSIBLINGS, required so that the child dialog box does not paint over the original file dialog
  • DS_3DLOOK, so that consistency of the look of the controls in the child dialog and the original dialog is preserved
  • DS_CONTROL, allows the user to navigate through the controls of the customized dialog with TAB or navigation keys

When using the template, the following should be done for the OPENFILENAME structure:

  • if the template is a resource in an application or DLL library, then:
    • Flags should contain OFN_ENABLETEMPLATE
    • hInstance must point to the module containing the resource
    • lpTemplateName should contain the template name
  • if the template is already in memory then
    • Flags should contain OFN_ENABLETEMPLATEHANDLE
    • hInstance member must identify the memory object that contains the template

The following code shows how to display a customized file dialog with a template with the ID set to “DIALOG_PREVIEW”:

	CFileDialog fileDialog(TRUE, NULL, NULL, OFN_HIDEREADONLY, _T("All files (*.*)|*.*||"));

	fileDialog.m_ofn.Flags |= OFN_ENABLETEMPLATE;
	fileDialog.m_ofn.hInstance = AfxGetInstanceHandle();
	fileDialog.m_ofn.lpTemplateName = _T("DIALOG_PREVIEW");

	fileDialog.DoModal();

The common file dialog is expanded on the sides so that the new controls have enough space. There are several rules that apply to this repositioning. I will explain them and exemplify with some images.

  • By default all the controls from the custom dialog are placed below the controls from the original file dialog. The following images show a simple dialog template with a check box and a static control (for a preview). By default, these controls are placed at the bottom of the dialog.
    Simple dialog template

    Simple dialog template


    Custom dialog with preview controls placed at the bottom

    Custom dialog with preview controls placed at the bottom

  • If the dialog template contains a static control with the id stc32 (defined in DLG.h), the controls will be positioned relative to this control (with the original dialog being displayed in its placed, in the original size).
    • all controls above and to the left of stc32 are positioned above and to the left of the original controls, with the same amount.
      Template with stc32 control position on the right and middle

      Template with stc32 control position on the right and middle


      Custom File Fialog with Preview controls on the top left

      Custom File Fialog with Preview controls on the top left

    • all controls below and to the right of stc32 are positioned below and to the right of the original controls.
      Template with stc32 control position on the left and middle

      Template with stc32 control position on the left and middle


      Custom File Fialog with Preview controls on the top and on the right

      Custom File Fialog with Preview controls on the top and on the right

Base on that, if you want to place the preview controls on the right (as I would do), you’d have to place the stc32 control on the left of all the controls from your template. In other words, the template needs to look like this:

Template with stc32 on the left of all controls

Template with stc32 on the left of all controls

The resulting file dialog would look like this:

Custom File Dialog with Preview Controls on the right side

Custom File Dialog with Preview Controls on the right side

Note: In the above images the stc32 control had the border style set one one hand to make the control visible on the dialog template and on the other hand to have the the original file dialog controls more visible within the resulting file dialog. You wouldn’t do that with an actual file dialog.

As you could see from the sample code above, it’s very simple to extend the common file dialog. Of course, the part I haven’t shown so far is how to make use of these additional controls. But that is very simple. You just derive CFileDialog, add handlers for the new controls, implement all the logic you want, and instead of instantiating a CFileDialog object you instantiate an object of your derived class. In a following post I will explain how you can add preview functionality to such a custom file dialog.

You can read more about this topic in the following articles:

, , , , Hits for this post: 9057 .

Concepts were supposed to be an important new feature in C++0x. They were meant to allow programmers to specify properties (like constraints) for templates, allow compilers to do some optimization and tools to do some formal checking on the code. After years of debate, the standard committee found them “untried, risky and controversial” and ruled them out last month during their meeting in Frankfurt.

Danny Kalev, a former member of the C++ standard committee, wrote about this controversial removal, and later interviewed Bjarne Stroustrup about the concepts and the future of C++. You can read this interview, published on DevX.com, here.

You can find more about concepts in this paper by Bjarne Stroustrup.

, , , Hits for this post: 4757 .

In a recent post I wrote about Code Contracts in .NET. Now you can find a more detailed article on this topic at sharparena.com. In this article I’m providing more information and examples on:

  • pre-conditions
  • post-conditions
  • object invariants
  • asserts and assumptions
  • quantifiers

In additions, you should check the official user documentation, which can be found here.

, , , , Hits for this post: 7715 .

Visual Studio 2010 has support for code contracts that allow to express pre-, post-conditions and invariants to your .NET code.

Let’ say you want to create a function to return a random value in a range. This could look like it:

    class Program
    {
        Random rng = new Random();

        public int GetRandom(int min, int max)
        {
            return rng.Next(min, max);
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            int n1 = p.GetRandom(10, 20);
            int n2 = p.GetRandom(10, 10);
        }
    }

However, at a rough analysis one can find two problems:

  • Second call to GetRandom(), is not well formed, because the range is 0
  • Radnom.Next returns a value greater or equal to the first argument, and lower than the second.

What code contracts provide is a mean to check that some statements, like:

  • maximum value of the range should always be greater than the minimum value
  • returned value should always be in the interval, equal or greater than the minimum, and equal or less than then maximum

The first is a pre-requisite, and the second is a post-requisite. We can specify those with:

        public int GetRandom(int min, int max)
        {
            Contract.Requires(max > min);
            Contract.Ensures(Contract.Result() >= min &&
                             Contract.Result() <= max);

            return rng.Next(min, max);
        }

The Contract class is available in namespace System.Diagnostics.Contracts. To enable the static checking, you have to go to Project Properties > Code Contracts and select "Perform Static Contract Checking."

Code Contracts Property Page

Code Contracts Property Page

When you build, you get the following warnings:

Code Contracts warnings

Code Contracts warnings

The first says that the call GetRandom(10, 10) does not match the pre-condition. The second warning indicates that the post-condition is not met. It isn't possible to know whether Random.Next() returns a value that hods the post-condition. But if you check the "Perform Runtime Contract Checking" it asserts at runtime, when the return value is outside the interval (not possible with this code sample).

You can read more about code contracts on the BCL team's blog. It features a list of possible constructs for pre- and post-requisites, but also object invariants.

Code Contracts are also available for Visual Studio 2008. For downloads and additional information check the following links:

, , , , Hits for this post: 13303 .

It is often that I see people using namespace directives in header files. This is a bad practice maybe not enought explained, so I will try to clarify why one should always avoid this.

When you are using a using directive (such as using namespace std) or using declarations (such as using std::cout) you are bringing into the current namespace (either the global one or a named one) all the entities from the specified namespace (in the case of a using directive) or the entities specified with using declarations. Header files are meant to be included in sources files (usually more that just one source file) and the order of the include statements is most likely different.
If entities (types, functions, constants, etc.) with coliding names are brought into the same translation unit (source file) via different header files then the compiler will trigger errors due to ambiguities.

The following example will demonstrate this aspect. Suppose that you have an own list implementation in a file called mylist.h.

#pragma once 

namespace mycontainers
{
   class list
   {

   };
}

and you make use of this container in a class called foo, but in the header you are using a namespace directive to avoid writing the fully qualified name for list.

#pragma once
#include "mylist.h"

using namespace mycontainers;

class foo
{
   list mylist_;
};

However, a second class, called bar, is using the STL list, and also using a namespace directive.

#pragma once
#include < list >

using namespace std;

class bar
{
   list< int > mylist_;
};

All good as long as you use foo and bar separatelly. But the moment you need to include them both in the same source file (maybe directly, maybe via another headers) errors arise.

#include "foo.h"
#include "bar.h"

int main()
{
   foo f;

   return 0;
}

Here are the errors:

1>d:mariusvc++win32_testbar.h(9) : error C2872: 'list' : ambiguous symbol
1>        could be 'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'
1>        or       'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'
1>d:mariusvc++win32_testbar.h(9) : error C2872: 'list' : ambiguous symbol
1>        could be 'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'
1>        or       'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'

Of course, if you switch the order of #includes in you get another error:

1>d:mariusvc++win32_testfoo.h(8) : error C2872: 'list' : ambiguous symbol
1>        could be 'd:mariusvc++win32_testmylist.h(6) : mycontainers::list'
1>        or       'c:program filesmicrosoft visual studio 9.0vcincludelist(95) : std::list'

A second, more hard to spot error is explained by Sutter and Alexandrescu in C++ Coding Standards – 101 Rules, Guidelines, and Best Practices.
When you make use of a using declaration (using std::list), a snapshot of the used entity is taken. All later references to this entity are based on this snapshot. They provide the following example:

// sample 1
namespace A
{
   int f(double);
}

// sample 2
namespace B
{
   using A::f;
   void g();
}

// sample 3
namespace A
{
   int f(int);
}

// sample 4
void B::g()
{
   f(1);
}

When using A::f is encounted, a snapshot of A::f is taken from what was found so far. Only f(double) was declared already, f(int) is found only later.
So though this later overload was a better match for f(1) it would be ignored, because it wasn’t known at the time of the using declaration.

This issue complicates more if each of the first 3 samples were in different files. Then the order of the $include directives in the file that contains the 4th sample would dictate which overload of f() to be used.
And if sample 4 was itself in a header, other that the first 3, the order of the includes would become even more critical.

For these reasons, you should keep in mind never to use namespace directives or declarations in a header file. Instead use the fully qualified name for the types, functions, constants, etc. that you use, and leave the using directives for the source file exclusively.

, , , Hits for this post: 4934 .

I’ve found myself in situations when I spent lots of time debugging because of some variables declared in a base class were written in tens or maybe hundreds of places in the whole hierarchy, across one or multiple projects even. How could you find the right place where the value of such a variable changes? Well, not easy unless you make some changes to the code. In this article I’m going to show how to create a small wrapper to help you there.

But first, some rules of thumb:

  • Don’t make your variables public. This is pretty basic, but I’ve seen experienced people ignoring it; breaking it is a certain cause for maintenance problems.
  • When you have member variables in a base class that can potentially be assigned in many places across the hierarchy make it private, not protected, and provide Get/Set accessors to read and write it. Moreover, prefer to use this accessors in the base class too, instead of accessing it directly. This way you get only one entry point for reading/writing it, so spotting the places where the value changes will be trivial.

If you decide to go with the second rule that I mentioned I can bet you might be tempted to avoid the last advice and write it directly in the base class. Or if you won’t, one of your teammates will. To enforce that, you can use a wrapper class like the one show below.

template < typename T >
class ExplicitWriteVariable
{
	T value_;

	// do not allow assigning values
	T& operator=(const T& val);

public:
	ExplicitWriteVariable()
	{
	}

	explicit ExplicitWriteVariable(const T& val): value_(val)
	{
	}

	bool operator==(const ExplicitWriteVariable< T >& rhv)
	{
		return value_ == rhv.value_;
	}

	bool operator!=(const ExplicitWriteVariable< T >& rhv)
	{
		return value_ != rhv.value_;
	}

	bool operator==(const T& rhv)
	{
		return value_ == rhv;
	}

	bool operator!=(const T& rhv)
	{
		return value_ != rhv;
	}

	// allow assignment of the wrapper objects, and use Set for modifying the wrapper value
	ExplicitWriteVariable< T >& operator=(const ExplicitWriteVariable< T >& rhv)
	{
		if(this != &rhv)
		{
			Set(rhv.value_);
		}
		return *this;
	}

	// operator T is used for getting the wrapped value
	operator T () const
	{
		return value_;
	}

	// this is the only entry point for setting the value of the variable
	void Set(const T& val)
	{
		value_ = val;
	}
};

This template class has the following characteristics:

  • provides a default constructor and an explicit constructor
  • the assignment operator is made private and not implemented, which means you cannot use an object of this type on the left side of an assignment
  • provides the operator T() which allows to read the value without needing an explicit Get accessor
  • provides a Set accessor for changing the wrapper value; this is the only possible entry point for writing
  • has some comparison operators

If you use this to wrap variables in a base class you don’t make it private, but protected in the base class, otherwise you’ll have to provide get/set accessors for the ExplicitWriteVariable object itself. The lacking of operator= will force you though to use the Set() method explicitly.

Here are some samples for using the class:

void Print(int val)
{
	std::cout << val << std::endl;
}

int main()
{
	ExplicitWriteVariable< int > val(10);

	Print(val);
	if(val % 10 == 0) std::cout << "multiple of 10" << std::endl;

	val.Set(43);

	Print(val);
	if(val % 2 == 1) std::cout << "odd number" << std::endl;

	return 0;
}
10
multiple of 10
43
odd number

The following produces an error:

ExplicitWriteVariable< int > val(10);
val = 43; // error C2248

, , , Hits for this post: 4120 .