Issue When Using [] Operator To Access Elements Of A map

January 29, 2009

I had the habit of using [] operator to access elements of a map. For example, if we have

map<int, int> myMap, to get the element corresponding to 10, we can use

myMap[10]. This is perfectly ok as long as we have an element corresponding to 10. But, what if we don’t have one corresponding to 10?

There lies the problem. In this situation, myMap is already added with a default elemnent corresponding to 10 ([] operator provides no facility to validate if an element exists) and in the above situation, it is 0. As a result, a new (unwanted) element is added to the map (we can see that the size of map has been incremented by 1).

So a better alternative is to use the find() function associated with map. It does not add an element and if the element is not found, it will return map::end().

The example given below illustrates this.

#include

#include
using namespace std;

int main()
{
   map myMap;
   cout << "Size of myMap = " << myMap.size() << '\n';   // will be 0    int content = myMap[0];    // Now the size of myMap will be 1 as we used the [] operator    // and the value of content = myMap[0] = 0    cout << "Size of myMap = " << myMap.size() << '\n';       // Instead, if we use find, the size will not change.    // It will look for the element only.    map::const_iterator it = myMap.find(1);    // Here the element has not been found. So it = myMap.end()    cout << "Size of myMap = " << myMap.size() << '\n';   // will be 1 only     return 0;    } [/sourcecode] So the best practice is to avoid [] operator for accessing individual elements of a map.

Advertisements

How To Watch A Variable Even After Its Scope Is Over

January 19, 2009

Noramally, the value of a variable declared in a function can be seen in the watch window only when the control is inside that function itself (eg. When the above function calles a new function and if we step into the new function.) . Let’s discuss an example.

void SomeFunction()
{
   int myVariable = 20;
}
int main()
{
   int myVariable = 10;
   SomeFunction();
   return 0;   
}

In the above example, if I put a break point in the function main after the statement int myVariable = 10; I can see the value of myVariable in the watch window as follows.

break-point-in-main4

Now, if I put another break point in SomeFunction() after the statement int myVariable = 20;, when th execution flow reaches there, the watch window will show the value of myariable as 20 only.

So we have lost the value of myVariable declared in main(), eventhogh it lifetime is not over now.

How To Add a Permanent watch

We can still view the value of myVariable declared in main() inside the function SomeFunction(). For this, we will use the address of memory location (rather than the variable name) in which myVariable has been declared in main(). We can view the contents of this memory location as long as it has life in the program.

When the control reaches the break point in main(), take the address of myVariable using the & operator. Now we have a valid memory location address (a pointer). Still, it can be a raw pointer. So cast it to the correct type (int, in this case, as myVariable is of type integer) as

(int*)(address of myVariable)

adding-a-watch1Now see how the watch window shows the value we have stored, when the control reaches the second break point.

watching-the-old-variable1


How To Handle new Operator Failure

January 15, 2009

new operator is used to allocate memory in C++. Though it is rare that a modern day computer is not able to allocate memory for our program, still there may be situations where we have to face situations where the new operator fails. The function set_new_handler will divert the flow to a user function when the new operator fails. A simple example is given below.

#include
using namespace std;

// Function to be called when the new operator fails
void NewHandler()
{
   cout << "Out of memory" << '\n';    exit(0); }   int main() {    // Set the function to be called when new operator fails    set_new_handler(NewHandler);    while (true)    {       new int[50000000];   // Hope this will fail after a few iterations       cout << "Successful so far" << '\n';    }    return 0; } [/sourcecode] In the above example, the function NewHandler() will be called when the memory allocation using new operator fails.

Some Background Info

set_new_handler will store the function NewHandler() in a static new handler pointer. This new handler is used by operator new.


How To Get The Screen Resolution In Pixels

January 7, 2009

The function GetWindowRect(), defined in WinUser.h, is able to give the current screen resolution. The declaration of GetWindowRect() is


BOOL
WINAPI
GetWindowRect(
    __in HWND hWnd,
    __out LPRECT lpRect);

We can give a handle to the current desktop window to the above function as input. A sample implementation for getting the current screen resolution is given below.

#include “wtypes.h”
#include
using namespace std;

// Get the horizontal and vertical screen sizes in pixel
void GetDesktopResolution(int& horizontal, int& vertical)
{
   RECT desktop;
   // Get a handle to the desktop window
   const HWND hDesktop = GetDesktopWindow();
   // Get the size of screen to the variable desktop
   GetWindowRect(hDesktop, &desktop);
   // The top left corner will have coordinates (0,0)
   // and the bottom right corner will have coordinates
   // (horizontal, vertical)
   horizontal = desktop.right;
   vertical = desktop.bottom;
}

int main()
{       
   int horizontal = 0;
   int vertical = 0;
   GetDesktopResolution(horizontal, vertical);
   cout << horizontal << '\n' << vertical << '\n';    return 0; } [/sourcecode]


How To Call A Managed Dll From Unmanaged Code

January 2, 2009

I here illustrate how a dll written in C# is called in C++ (without CLR).

Make a DLL in C#

Let’s make a small dll (MathLibrary.dll) in C# which provides a public API for adding two numbers. Start Visual Studio, start a new project in Visual C# and select the type of the project as class library. This is how my code for DLL looks like.


using System;
using System.Collections.Generic;
using System.Text;

namespace MathLibrary
{
   public interface IAddClass
   {
      int Add(int a, int b);
   }
   public class CAddClass : IAddClass
   {
      public int Add(int a, int b)
      {
         return a+b;
      }
   }
}

It has a namespace MathLibrary which contains an interface IAddClass and its implementation CAddClass. The public API Add(int a, int b) is provided which can add two numbers supplied.

We have to attach a key file to our DLLl. To generate the key file, go to Visual Studio command prompt (From Start menu –> Programs –> Microsoft Visual Studio 2005 –> Visual Studio Tools). n the command prompt, type

sn.exe -k MyKeyFile.SNK

You can see that MyKeyFile.SNK is generated in the visual studio directory (the command prompt will display where it has been generated). Copy it to the source directory of the dll.  Now edit the AssemblyInfo.cs in visual studio and add/edit the following lines.

[assembly: ComVisible(true)]
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("MyKeyFile.SNK")]

Make sure that MyKeyFile.SNK is in the correct path specified.

Now you can build the DLL (or press Ctrl + Shift + B).

Copy the dll to the directory of the source (C++ program withour CLR option) from where it is to be called.

Register the DLL

Now you have to register the managed dll for using in the unmanaged C++ code. Again take the visual studio command prompt and enter the following command.

RegAsm.exe [including full path] MathLibrary.dll /tlb:MathLibrary.tlb /codebase

We have generated a TLB file, which  contains the type library of different types used in the DLL. The dll is now registered and ready for use in unmanaged code.

Call the DLL from Unmanaged code

The .NET component (dll) can be used as a COM in unmanaged code. So a sample code is provided below which uses the managed DLL as COM.


#include “stdafx.h”
#include

// Import the type library in DLL
#import “MathLibrary.tlb” raw_interfaces_only

using namespace MathLibrary;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
   // Initialize the COM interface
   HRESULT hr = CoInitialize(NULL);
   // Make a smart pointer to the IAddClass interface in DLL
   IAddClassPtr pIAddClass(__uuidof(CAddClass));   
   // Add two numbers using the ADD API
   long result = 0;
   hr = pIAddClass->Add(10, 20, &result);
   // Release the COM interface
   CoUninitialize();
   // Display the results
   cout << result << '\n';      return 0; } [/sourcecode]