Feeds:
Posts
Comments

Archive for August, 2004

More on References

Here’s some more stuff on references. As Mike Dunn commented on the previous blog entry, a reference cannot be re-referenced (for lack of a better word) to a different object. So if you have a reference, then it will always be an alias for the very same object it was an alias for when it got created. This is similar to a const pointer, but pointers and references are not the same thing at all – so don’t go about thinking that a reference is a const pointer.

You can also use references as function returns, including class member function returns. See the following code snippet :-

int Func1(...)
{
  //...
}

int& Func2(...)
{
  //...
}

//...

int i = Func1(...);

int j = Func2(...);

When Func1 is called, the return value is passed by value, which means a new temporary value is created to which the return value is copied to and then again copied to the variable i. But when Func2 is called, the temporary value is not created though the second copying is still done – but that is part of program logic and not to do with the functions. Obviously this has more value in terms of efficiency when you are returning a large object, rather than a simple native type as you are in the above example. But then, when you are returning a reference, you have to be very very careful that you do not return a temporary automatic variable with scope only within the function, else you will have disastrous results. Because now the reference is an alias for an object that does not exist anymore.

Using references as return values has a remarkable side-effect – the function return is now an l-value. See the following code snippet :-

class A
{
public:
  A(int y):m(y){}
  A(const A&)
  {
    printf("*** copy ctor ***\r\n");
  }
  int& Num()
  {
    return m;
  }
private:
  int m;
};

A g_A(5);

A& GetA()
{
  return g_A;
}

int _tmain(int argc, _TCHAR* argv[])
{
  int x = GetA().Num(); //l-value usage
  printf("%d\r\n",x);

  A a(100);
  int i = a.Num() = 99; //l-value usage
  printf("%d\r\n",i);
  printf("%d\r\n",a.Num());

  return 0;
}

You can see how I’ve been able to use syntax like GetA().Num() and a.Num() = 99. We can actually write fancy looking code (which saves us some typing) such as :-

class A
{
public:
  A():m(0){}
  A& Add1()
  {
    m++;
    return *this;
  }
  A& Mul7()
  {
    m *= 7;
    return *this;
  }
  A& SquareNum()
  {
    m *= m;
    return *this;
  }
  void Show()
  {
    cout << m << endl;
  }
private:
  int m;
};

int _tmain(int argc, _TCHAR* argv[])
{
  A a;
  a.Add1().Mul7().SquareNum();
  a.Show();
  return 0;
}

a.Add1().Mul7().SquareNum() is actually a shorter form of a.Add1(); a.Mul7(); a.SquareNum(). Those of you who’ve used MFC might remember how CListView::GetListCtrl actually returns a CListCtrl& which lets you write code like GetListCtrl().InsertColumn(...) which is sorta easy on the eyes.

Read Full Post »

C++ References

These days, I spend most of my free time trying to understand the C++/CLI language and syntax, and very often I have to refresh my native C++ knowledge. So, expect some basic C++ stuff during the next few weeks, and if you are an experienced C++ coder, then please skip these entries rather than going through then and then feeling annoyed at having read something you knew for years. These entries are meant for relatively inexperienced C++ developers :-)

In C++, a reference is an alias for a variable – C did not have the concept of a reference. You specify that a variable is a reference type by adding an & to the right of the typename.

  • int i = count; Here, i is a normal variable and the value of count is copied to i. Changing the value of count will have no effect on i.
  • int& j = count; Here j is a reference which is an alias for count. Changing the value of count is equivalent to changing the value of j and vice-versa.

References are a lot more efficient as function arguments than pass-by-value arguments, because in the latter case, a new temporary copy of the passed object has to be created. See the following code snippet :-

class A
{
public:
  A(){}
  A(const A&)
  {
    cout << "A::copy_ctor" << endl;
  }
};

void Func1(A a)
{
  cout << "In Func1" << endl;
}

void Func2(A& a)
{
  cout << "In Func2" << endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
  A a;
  cout << "Calling Func1" << endl;
  Func1(a);
  cout << "Calling Func2" << endl;
  Func2(a);

  return 0;
}

/* Output :-

	Calling Func1
	A::copy_ctor
	In Func1
	Calling Func2
	In Func2

*/

As you can see, calling Func1 results in the copy constructor of the class A being invoked, whereas calling Func2 does not make a copy as it expects a reference as argument. In cases where the object passed is large and where the creation of a copy is time-consuming or memory-wasting, references do provide a more elegant and efficient option. Of course you could use a pointer type and modify the prototype of the function to void Func(A* pA) but now you would have to check for a null pointer, and the caller might often have to do something like A a; Func(&a); which is not very aesthetic looking.

BTW, you have to be wary of something if you have a C background. Take a look at the following code :-

void DoStuff(A& a)
{
  a.m = 10; //modify a
}

int _tmain(int argc, _TCHAR* argv[])
{
  A a;
  DoStuff(a);

  //...

Now in C, you’d expect that DoStuff(a) won’t modify a as a is expected to be passed by value. In C++, this depends on whether DoStuff takes a reference or a normal variable. But then again, the solution is very straightforward, all you need to do is change the function prototype to take a reference to a const:-

void DoStuff(const A& a)
{
  a.m = 10; //Won't compile - C2166
}

Now, you won’t be able to inadvertently corrupt an object that you pass to the function. There’s lot more to talk about on references, but I’ll probably do them in a future entry.

Read Full Post »

A geek's nightmare

Dreaming of being an orphaned ref object that’s being hunted down by the Garbage Collector. I can imagine the GC, dressed in a sinister looking black suit, shouting at me asking me to slow down, and I run away as fast as I could through the partially compacted CLI heap, making loud protests of how my finalizer needs some more time to finish executing. Eventually I trip on a 2nd generation String object, having got my shoe laces entangled with one of the taller alphabets it contained (might have been an f or perhaps a y – damned letters) and fall down. The GC comes near me and laughs aloud; horribly, cruelly, brutally… My last thought is, “Oh, how I wish I weren’t a managed object!”.

Read Full Post »

Here’s a technique to run a GUI application in a hidden manner. It’s not a big deal really and is not meant for espionage or any such activity; rather it’s just an useful trick to know if you want to run a desktop game when you are at work and you don’t want your boss to see it. Basically we create a second desktop, switch to it, and run our apps on it.

bool RunAppInDesktop(
    const char* szDesktop, //A name for the new desktop
    const char* szAppPath, //Fully qualified path to your app
    bool bPrompt = false   //Set true to get a mock messagebox
);

If the bPrompt parameter is false, the new app is spawned on the new desktop and we switch back to the current desktop quickly; if you set it to true, the mock messagebox pops up and remains on screen preventing the new desktop from closing. Play your games or watch you videos or whatever and when your boss comes near you, close the messagebox to go back to the default desktop. When he/she leaves, switch back again and your apps will be still running there just as you had left them – like obedient little puppies :-)

When you are done, close all the apps and then dismiss the messagebox; the second desktop will now be closed and destroyed.

Here is the full code listing :-

bool RunAppInDesktop(const char* szDesktop,
  const char* szAppPath, bool bPrompt = false);

//... your code goes here

bool RunAppInDesktop(const char* szDesktop,
           const char* szAppPath,
           bool bPrompt /*= false*/)
{
  bool ret = true;
  HDESK horig = GetThreadDesktop(GetCurrentThreadId());
  HDESK hdesk = CreateDesktop(szDesktop,NULL,NULL,
    0,GENERIC_ALL,NULL);
  if(hdesk)
  {
    if(SetThreadDesktop(hdesk))
    {
      SwitchDesktop(hdesk);
      PROCESS_INFORMATION ProcessInfo;
      STARTUPINFO StartupInfo;
      ZeroMemory(&StartupInfo, sizeof(StartupInfo));
      StartupInfo.cb = sizeof StartupInfo ;
      char tmp[1024];
      strcpy(tmp,szDesktop);
      StartupInfo.lpDesktop = tmp;
      if(CreateProcess(szAppPath, NULL,
        NULL,NULL,FALSE,0,NULL,
        NULL,&StartupInfo,&ProcessInfo))
      {
        CloseHandle(ProcessInfo.hThread);
        CloseHandle(ProcessInfo.hProcess);
      }
      else
        ret = false;
      if(bPrompt)
        MessageBox(NULL,"Close all your apps now",
          "Prompt",MB_OK);
      else
        Sleep(300);
      SwitchDesktop(horig);
      SetThreadDesktop(horig);
    }
    else
      ret = false;
  }
  else
    ret = false;
  CloseDesktop(hdesk);
  return ret;
}

Read Full Post »

I am not sure how many C++ developers out there use the explicit keyword or are even aware of its existence. It was only today that I actually took a look at what it does and I’d like to thank my friend Rama Krishna for some vauable pointers (not the C/C++ kind) he gave me. Before I tell you what explicit does, lemme show you some code :-

class A
{
    friend class B;
public:
    A(int q) : _y(q)
    {
    }
private:
    int _y;
};

class B
{
public:
    B(A a) : _x(a._y)
    {
    }
    void Show()
    {
        printf("%d\r\n",_x);
    }
private:
    int _x;
};

Okay, nothing fancy about that code, eh? Now, take a look at this :-

int _tmain()
{
    B b = 17;
    b.Show();
    return 0;
}

I bet that looks pretty confusing for people who are not familar with conversion constructors. Basically, what happens is that the B b = 17 is considered as B b(17) and this is taken as B b(A(17))! Pretty crazy it might seem, but apparently, lot of guys have been using this style for years. (Thanks to Mike Dunn for pointing out an error in my original explanation; the error has been corrected)

The explicit keyword is used to specify that the constructor cannot take part in implicit conversions. Just change your code as follows :-

class A
{
    friend class B;
public:
    explicit A(int q) : _y(q)
    {
    }
private:
    int _y;
};

class B
{
public:
    explicit B(A a) : _x(a._y)
    {
    }
    void Show()
    {
        printf("%d\r\n",_x);
    }
private:
    int _x;
};

Now you’ll have to explicitly write B b(A(17)) or else get a compiler error.

BTW, just to verify if I am the only idiot in town who had never heard of this stuff, have any of you guys ever used this weird conversional syntax when constructing objects?

Read Full Post »

People new to C/C++ are sometimes confused about the difference between a const pointer and a pointer to const. A const pointer essentially means you can’t change the pointer variable itself, but you can change the value it points to. A pointer to const means you can change the pointer but not what it points to. You can use them both together and have a const pointer to a const. The code snippet below should make it really clear I hope.

//pointer to a const
void f1()
{
    int i = 100;
    const int* pi = &i;
    //*pi = 200; <- won't compile
    pi++;
}

//const pointer
void f2()
{
    int i = 100;
    int* const pi = &i;
    *pi = 200;
    //pi++; <- won't compile
}


//const pointer to a const
void f3()
{
    int i = 100;
    const int* const pi = &i;
    //*pi = 200; <- won't compile
    //pi++; <- won't compile
}

Read Full Post »

Follow

Get every new post delivered to your Inbox.