Thursday, May 29, 2008

C++ puzzles #6

Win32 Equivalents for C Runtime Functions

Many of the C runtime functions have direct equivalents in the Win32 application programming interface (API). However, when you use C-Runtime functions, you need to have C-Runtime startup code and this could increase the size of your applications or DLLs. Instead, you can use those Win32 API functions to perform the same tasks and they don't require any start up code thereby reducing the size of your Applications or DLLs. Here's some examples:

Buffer Manipulation:

  memcpy  --> CopyMemory
  memmove --> MoveMemory
  memset  --> FillMemory, ZeroMemory

Character Classification:

  isalnum -> IsCharAlphaNumeric
  isalpha -> IsCharAlpha, GetStringTypeW (Unicode)
  islower -> IsCharLower, GetStringTypeW (Unicode)
  tolower -> CharLower
  toupper -> CharUpper

Stream Routines:

  sprintf  -> wsprintf
  vsprintf -> wvsprintf

String Manipulation:

strcat, wcscat   -> lstrcat
  strcmp, wcscmp   -> lstrcmp
  strcpy, wcscpy   -> lstrcpy
  _strupr, _wcsupr -> CharUpper, CharUpperBuffer

These are just some popular C-Runtime functions that have equivalencies in the Win32 API.

How to Make a Private Member Public

You can make a privately inherited member public by specifying its access modifier in the derived class. For example:

#include <iostream.h>
class base
      int a;
      int b;
      void show_a(void)
      void show_b(void)
class derived:private base
int main(void)
     derived d1;

In the above example, the class named base is privately inherited into the class derived, making the variables a, b, and member functions show_a(), show_b() private, but making a declaration of a and show_a() in the public section of derived, making them public again.

C++ Smart Pointers

C++ smart pointers are the idea of using a selector to access a class. This gives the class writer an option to control access to class members and function. For example, if you wanted to count references to the object and autodelete it when the count goes to zero. Here's a simple example:

class CA {
        void func() { // ... }

This will be a smart pointer to the CA class:

class CPtrA {
        CPtrA() : m_pA(new CA) { }
        ~CPtrA()  { delete m_pA; }
        CA* operator->() { return m_pA; }
        CA* m_pA;

Using the smart pointer:

        CPtrA pA;

Overloading operator= will give you an option to count references. You'll know about each pA = pOtherA by the user, and will be able to take the appropriate action.

C++ COM and CORBA rely heavily on smart pointers. The Standard Template Library also has an auto_ptr template, for your convenience.

Overloading and Overriding

Overriding a method suppresses the visibility of any overloads in the base class for the overridden method. Say you have a base class CBase where there are two trivial overloads:

class CBase {
 CBase ();
 Func (int param);
 Func (float param);

In the derived class, you overload Func:

class CDerived {
 CDerived ();
 Func (float param);

Say you do something like this:

CDerived derived;
int param = 1;
derived.Func (param);

You expect that CBase::Func (int) should be called as you have passed a parameter of type int and this method would be the best match. You'd be surprised.

If you run it in debug step by the step, you'll see that instead CDerived::Func (float) is called. Why? Because when you override a method, all the overloads in the base class for that method become invisible. What happens is that a conversion from int to float is made for param and then CDerived::Func (float) is called. Perhaps not exactly what you wanted to do.

Here's a workaround:

In CDerived, bring the overloads in the CDerived interface by using the C++ statement "using".

class CDerived {
 CDerived ();
 using CBase::Func;
 Func (float param);

Now everything's fine and the compiler will call CBase::Func (int) as you'd probably expected.

The Effects of Deleting an Array of Pointers

Suppose we have a class called A. A has a data member p which is a pointer to another object:

class A
 A() {p = new B[10];}
 int *p;

We also have an array of A objects that was allocated using new:

A * arr = new A[10];

The question is this: is the p member of A deleted when we delete arr? In other words, does the following statement delete the p member of each A object in arr?

delete [] arr;

Not necessarily. If class A doesn't have a destructor that explicitly deletes p, the delete statement above causes a memory leak. If, however, A has a destructor defined like this:

 delete [] p;

Then deleting arr will automatically invoke A's destructor, which will in turn delete the p member of each element in arr. To conclude, operator delete automatically invokes the destructor of its argument. However, it is the programmer's responsibility to make sure that that destructor releases all the dynamically allocated members of its object.

Registering a Function with std::set_unexpected

set_unexpected() takes a pointer to a user-defined function of the following type:

typedef void (*handler)();

Use set_unexpected() to register a user-defined routine that will be invoked when a function throws an exception not listed in its exception specification, use set_unexpected(). For example:

#include <except>
void my_handler() // will be called instead of terminate()
 write_to_log("a violation of an exception specification");
 // additional cleanup operations…
int main()
  // from now on, my_hanlder will be called in the event
  // of a function violating its exception specification

Differences Between C and C++ in the Interpretation of an Empty Parameter List

C and C++ differ in their interpretation of an empty parameter list. In the following function declaration:

void f(); // different meanings in C and C++

C++ treats f as a function that returns no value and takes no arguments, whereas in C it is treated as a function that returns no value and takes an unspecified list of arguments. Put differently, an empty parameter list in C++ is synonymous to void, whereas in C it means that the function can take any number of arguments of any type. To ensure backward compatibility with C and to avoid confusion, it’s customary to declare a function that takes no arguments as follows:

void f(void); // treated identically in C and C++

Passing Arrays by Value

It has already been said many times that (a) std::vector is preferred to c-style arrays, and (b) Arrays, vectors, and other data structures should preferably be passed by reference.

While this is sound advice in the general case, there may come a time when you want to pass a c-style array by value.

This is not simple since arrays decay to pointers on function calls. So, if you have:

   int a[] = { 1, 2, 3, 4, 5};

The actual argument to f() is a pointer to the first element of the array. In order to overcome it, wrap the array in a structure. This technique works both in C and C++, so I'll demonstrate it without using C++ specific features:

#include &;t;stdio.h>
#define SIZE 5
typedef struct
   int a[SIZE];
} Wrapper;
void f(Wrapper w)
   int i;
   for (i = 0; i < SIZE; ++i)
      w.a[i] = 0;
void main()
   Wrapper w = { { 1, 2, 3, 4, 5 } };
   int i;
   for (i = 0; i < SIZE; ++i)
      printf("%d ", w.a[i]);



No comments: