Index | Prev | Next

C & C++ Programming

What is a dangling pointer in C++?

A dangling pointer arises when you use the address of an object after its lifetime is over. This may occur in situations like returning addresses of the automatic variables from a function or using the address of the memory block after it is freed. The following code snippet shows this:

class CDanglingPointers
{
public:
  int *ptr;
  CDanglingPointers(int i)
  {
    ptr = new int(i);
  }

  ~CDanglingPointers()
  {
    delete ptr;
  }
  void PrintVal()
  {
    cout << "The value is " << *ptr;
  }
};

void SomeFunc(CDanglingPointers x)
{
  cout << "Say i am in someFunc " << endl;
}

int main()
{
  CDanglingPointers s1 = 10;
  SomeFunc(s1);
  s1.PrintVal();
}

In the above example when PrintVal() function is called it is called by the pointer that has been freed by the destructor in SomeFunc.

What is an adaptor class or Wrapper class in C++?

A class that has no functionality of its own is an Adaptor class in C++. Its member functions hide the use of a third party software component or an object with the non-compatible interface or a non-object-oriented implementation.

What is class invariant in C++?

A class invariant is a condition that defines all valid states for an object. It is a logical condition to ensure the correct working of a class. Class invariants must hold when an object is created, and they must be preserved under all operations of the class. In particular all class invariants are both preconditions and post-conditions for all operations or member functions of the class.

What do you mean by Stack unwinding in C++?

Stack unwinding in C++ is a process during exception handling when the destructor is called for all local objects between the place where the exception was thrown and where it is caught.

What are proxy objects in C++?

Objects that stand for other objects are called proxy objects or surrogates.
template < class T >
class Array1D
{
public:
  Array1D
  {
  }
  T& operator[] (int index);
  const T& operator[] (int index)const;

  Array1D operator[] (int index);
  const Array1D operator[] (int index) const;
};

The following then becomes legal:

Array2D<float>data(10, 20);
cout << data[3][6]; // fine

Here data[3] yields an Array1D object and the operator [] invocation on that object yields the float in position(3,6) of the original two dimensional array. Clients of the Array2D class need not be aware of the presence of the Array1D class. Objects of this latter class stand for one-dimensional array objects that, conceptually, do not exist for clients of Array2D. Such clients program as if they were using real, live, two-dimensional arrays. Each Array1D object stands for a one-dimensional array that is absent from a conceptual model used by the clients of Array2D. In the above example, Array1D is a proxy class. Its instances stand for one-dimensional arrays that, conceptually, do not exist.

What is a node class in c++?

A node class is a class that,
  1. relies on the base class for services and implementation
  2. provides a wider interface to the users than its base class
  3. relies primarily on virtual functions in its public interface
  4. depends on all its direct and indirect base class
  5. can be understood only in the context of the base class
  6. can be used as base for further derivation
  7. can be used to create objects.
A node class is a class that has added new services or functionality beyond the services inherited from its base class.

What is a container class? What are the types of container classes in C++?

A container class is a class that is used to hold objects in memory or external storage. A container class acts as a generic holder. A container class has a predefined behavior and a well-known interface. A container class is a supporting class whose purpose is to hide the topology used for maintaining the list of objects in memory. When a container class contains a group of mixed objects, the container is called a heterogeneous container; when the container is holding a group of objects that are all the same, the container is called a homogeneous container.

What is function overloading and operator overloading?

Function overloading: C++ enables several functions of the same name to be defined, as long as these functions have different sets of parameters (at least as far as their types are concerned). This capability is called function overloading. When an overloaded function is called, the C++ compiler selects the proper function by examining the number, types and order of the arguments in the call. Function overloading is commonly used to create several functions of the same name that perform similar tasks but on different data types.

Operator overloading allows existing C++ operators to be redefined so that they work on objects of user-defined classes. Overloaded operators are syntactic sugar for equivalent function calls. They form a pleasant facade that doesn't add anything fundamental to the language (but they can improve understandability and reduce maintenance costs).

What is the difference between hashmap and map?

Map uses a red-black tree as the data structure, so the elements you put in there are sorted, and insert/delete is O(log(n)). The elements need to be implement at least operator<.
Hashmap uses a hash, so elements are unsorted, insert/delete is O(1). Elements need to implement at least operator== and you need a hash function.

hash_map uses a hash table. This is "constant" time in theory. Most implementations use a "collision" hash table. What happens in reality is:

  • It creates a big table
  • You have a "hash" function for your object that generates you a random place in the table (random-looking, but the hash function will always return the same value for your object) and usually this is the mod of the actual 32-bit (or 64-bit) hash value with the size of the table.
  • The table looks to see if the space is available. If so it places the item in the table. If not it checks if the element there is the one you are trying to insert. If so it is a duplicate so no insert. If not, this is called a "collision" and it uses some formula to find another cell and this continues until it either finds a duplicate or an empty cell.
  • When the table gets filled up too much it resizes. An efficient (in time) implementation will store all the original hash values together with the elements so it won't need to recalculate the hashes when it does this. In addition, comparing the hashes is usually faster than comparing the elements, so it can do this whilst searching to eliminate most of the collisions as a pre-step.
  • If you never delete anything it is simple. However deleting elements adds an extra complexity. A cell that had an element in it which has been deleted is in a different state from one that was just empty all along, as you may have had collisions and if you just empty it, those elements won't be found. So there is usually some "mark". Of course now when we want to reuse the cell, we still have to recurse down in case there is a collision lower down, then remember to reuse the deleted cell.
  • The usual constraint is that your objects must be implemented to check for equality, but Dinkumware (or was it SGI) implemented theirs with operator< (slower but has the advantage of decoupling your elements and the type of associated container they can be stored in, although you still need a hash function to store in a hash).

The theory is that if you have a big enough table, the operations are constant time, i.e. it does not depend on the number of actual elements you have. In practice, of course, the more elements you have the more collisions occur.

std::map uses a binary tree. There is no need to define a hash function for an object, just strictly ordered comparison. On insertion it recurses down the tree to find the insertion point (and whether there are any duplicates) and adds the node, and may need to rebalance the tree so the depth of leaves is never more than 1 apart. Rebalancing time is relative to the depth of the tree too so all these operations are O(log N) where N is the number of elements.

The advantages of hash is the complexity The advantages of the tree is:

  • Totally scalable. It only uses what it needs, no need for a huge table or to pre-empt the size of the table, although hash may require less "baggage" per element than a tree.
  • No need to hash first, which for a good function can take longer than the comparisons would if the data set is not large.

One other issue with std::map is that it uses a single strictly-ordered comparison function whilst a "compare" function that returned -1, 0 or 1 would be a lot more efficient, particularly with the most commonly used key type, std::string, which already has this function implemented (it is char_traits::compare)

What are Functors ?

Functors are functions with a state. In C++ you can realize them as a class with one or more private members to store the state and with an overloaded operator () to execute the function. Functors can encapsulate C and C++ function pointers employing the concepts templates and polymorphism. You can build up a list of pointers to member functions of arbitrary classes and call them all through the same interface without bothering about their class or the need of a pointer to an instance. All the functions just have got to have the same return-type and calling parameters. Sometimes functors are also known as closures. You can also use functors to implement callbacks.

Can we store auto_ptr in STL containers?

STL Container may move elements around during reallocation. So The element should be copy constructible or assignable. But auto_ptr is neither.

When do you use volatile and register keywords?

The value of volatile variable can be changed even from outside of process. esp, in firmware programs the hardware writes/updates memory location of process. Register - telling the compiler to use CPU register to hold that variable. It upto the compiler decision to use register, other wise it simple ignore the keyword.

What is stack unwinding?

During exception handling when the destructor is called for all local objects in the stack between the place where the exception was thrown and where it is caught.
Index | Prev | Next