Protecting against uninitialized variables
The compiler I use (Visual C++ 2003) warns when I am reading from a
potentially uninitialized variable, unless that variable is a class
member. For example, I will be warned for doing the following:
void foo()
{
int x;
printf("%d", x); // warning!
}
But this doesn't produce any warning:
struct Foo { int x; };
void foo()
{
Foo myFoo;
printf("%d", myFoo.x); // undefined output
}
(I'm not sure if there are compilers out there that warn about this
problem; mine definitely does not.)
This has caused headaches in projects I've worked on, especially since
this sort of error isn't caught in Debug builds, making it hard to
notice & track down. To protect against this sort of error, I've
created a templated class called "safe_type," and I'm looking for
comments on its design -- possible issues, whether it's useful, etc.
It's designed to be used with built-in types (bool, int, float, etc)
and raw pointers. To reduce the size of this post, I've omitted the -
=, *=, /=, etc operators, since they're not particularly interesting.
Here's an example of how I intend safe_type to be used:
/* myBool will be initialized to false, myInt will be initialized to
0, and myBar will be initialized to NULL */
/* safe_bool and safe_int are typedefs for safe_type<bool> and
safe_type<int> */
struct Foo
{
safe_bool myBool;
safe_int myInt;
safe_type<Bar*> myBar;
};
And here's the class itself:
template <class T>
struct safe_type_traits;
template<>
struct safe_type_traits<bool>
{
static bool DefaultValue() { return false; }
};
template<>
struct safe_type_traits<int>
{
static int DefaultValue() { return 0; }
};
template<>
struct safe_type_traits<float>
{
static float DefaultValue() { return 0.0f; }
};
template <class T>
struct safe_type_traits<T*>
{
static T* DefaultValue() { return NULL; }
};
template <class T>
struct safe_type
{
private:
T m_val;
public:
safe_type() : m_val(safe_type_traits<T>::DefaultValue()) {}
safe_type(T val) : m_val(val) {}
safe_type& operator=(safe_type rhs) { m_val = rhs.m_val; return
*this; }
safe_type& operator=(T rhs) { m_val = rhs; return *this; }
// conversion operator
operator T() const { return m_val; }
// operator ->
T operator->() const { return m_val; }
// operator ==
template <class U> bool operator==(U rhs) { return (m_val == rhs); }
// operator !=
template <class U> bool operator!=(U rhs) { return (m_val != rhs); }
// operator +=
template <class U> safe_type& operator+=(U rhs)
{
m_val += rhs;
return *this;
}
// prefix ++
safe_type& operator++()
{
++m_val;
return *this;
}
// postfix ++
safe_type operator++(int)
{
safe_type old(*this);
++m_val;
return old;
}
// prefix --
safe_type& operator--()
{
--m_val;
return *this;
}
// postfix --
safe_type operator--(int)
{
safe_type old(*this);
--m_val;
return old;
}
};
typedef safe_type<bool> safe_bool;
typedef safe_type<float> safe_float;
typedef safe_type<int> safe_int;
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]