Saturday 10 August 2013

C++ Interview Questions

Can a member function template be virtual?



Think about it for a while:

Q.1. How could you make a templated virtual function?
Q.2. What's its signature?
Q.3. How many vtable entries do you reserve?
Q.4. How would you distinguish between an override/hide and an overload?


Templates are all about the compiler generating code at compile-time. Virtual functions are all about the run-time system figuring out which function to call at run-time.

Once the run-time system figured out it would need to call a templatized virtual function, compilation is all done and the compiler cannot generate the appropriate instance anymore. Therefor, you cannot have virtual member function templates.

h<int>(&f<int>());


 

Making an API C Callable



A C++ function is not necessarily made C callable by prototyping the C++ function with the extern C keywords. While the extern C keyword prevents the name of the C++ from being mangled, there are other issues to be considered.

C vs C++ Issues

- C does not use classes. Therefore, it cannot pass classes by value. If a C++ API function requires that a class be passed by value as its input, it is not C callable, regardless of whether it is prototyped with the extern C keyword. This leads to the following rule: API functions must not pass classes by value.

- C does have "void pointers". A C void pointer points to the address of a class just as it points to a structure. Therefore, a C++ API function would be C callable if its class arguments were passed by address (BODY*) or by reference (BODY&). Either method allows the API function to be called from C.

 

What is difference between "new operator" and "operator new"?



The difference between the two is that operator new just allocates raw memory, nothing else. The new operator starts by using operator new to allocate memory, but then it invokes the constructor for the right type of object, so the result is a real live object created in that memory. If that object contains any other objects (either embedded or as base classes) those constructors as invoked as well.

Following is the quote from More Effective C++ book from Scott Meyers:

The new operator calls a function to perform the requisite memory allocation, and you can rewrite or overload that function to change its behavior. The name of the function the new operator calls to allocate memory is operator new.

 

Is there any way a C/C++ program can crash before main()?



There are many possibilities.

First, we need to understand what actually goes on before main is executed:

    Load of dynamic libraries
    Initialization of globals
    One some compilers, some functions can be executed explicitly

Now, any of this can cause a crash in several ways:

    the usual undefined behavior (dereferencing null pointer, accessing memory you should not...)
    an exception thrown > since there is no catch, terminate is called and the program end

It's really annoying of course and possibly hard to debug, and that is why you should refrain from executing code before main as much as possible, and prefer lazy initialization if you can, or explicit initialization within main.

Of course, when it's a DLL failing and you can't modify it, you're in for a world of pain.

 

What happens when you run a program?



On Windows, first the image is loaded into memory. The kernel analizes which libraries (read "DLL") it is going to require and loads them up too. Initialization of globals happen.

It then edits the program image to insert the memory addresses of each of the library functions it requires. These addresses have a space in the .EXE binary already, but they are just filled with zeros.

Each DLL's DllMain() procedure then gets executed, one by one, from the most required DLL to the last, like following an order of dependences.

Once all libraries were loaded and got ready, finally the image is started, and whatever happens now will depend on language used, compiler used, and the program routine itself.


Client request to run application
  ->Shell informs kernel to run binary
  ->Kernel allocates memory from the pool to fit the binary image into
  ->Kernel loads binary into memory
  ->Kernel jumps to specific memory address
  ->Kernel starts processing the machine code located at this location
  ->Kernel pops current location into an execution stack
  ->Kernel jumps out of current memory to a shared memory location
  ->Kernel executes code from this shared memory location
  ->Kernel pops back the last memory location and jumps to that address
  ->If machine code has stop
  ->Kernel releases memory back to pool

 

Where does static or non-static variables stay? I mean in memory. and, When are static or non-static variables initialized?



They can go wherever the compiler (or linker or loader) wants to put them in memory, the C and C++ standards don't mandate that level of detail. They only mandate the behaviour.

Typically, static members are initialised once, either on program startup (including at compile time so that they're simply loaded in an already-initialised state) or immediately before first use.

   


 

Difference between WinMain,main and DllMain in C++?



WinMain is used for an application (ending .exe) to indicate the process is starting. It will provide command line arguments for the process and serves as the user code entry point for a process. WinMain (or a different version of main) is also a required function. The OS needs a function to call in order to start a process running.

"DllMain" is used for a DLL to signify a lot of different scenarios. Most notably, it will be called when

    The DLL is loaded into the process: DLL_PROCESS_ATTACH
    The DLL is unloaded from the process: DLL_PROCESS_DETACH
    A thread is started in the process: DLL_THREAD_ATTACH
    A thread is ended in the process: DLL_THREAD_DETACH

DllMain is an optional construct and has a lot of implicit contracts associated with it. For instance, you should not be calling code that will force another DLL to load. In general it's fairly difficult function to get right and should be avoided unless you have a very specific need for it.

This is a good explanation ut it needs to also specify that these are required entry points for the three different types of "executables" (console app, windows app, windows DLL).

A DLL can run directly if you're using "rundll32.exe"

WinMain simply means that there will be NO console window allocated for the app, and its stdin and stdout have nowhere to go. All the guts of Windows API (such as event loop, registration of classes, window creation) still need to be done manually. Also, programs using main() can have windows too.

 

Return value optimization



The following example demonstrates a scenario where the implementation may eliminate one or both of the copies being made, even if the copy constructor has a visible side effect (printing text).[4] The first copy that may be eliminated is the one where C() is copied into the function f's return value. The second copy that may be eliminated is the copy of the temporary object returned by f to obj.

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "A copy was made.\n"; }
};

C f() {
  return C();
}

int main() {
  std::cout << "Hello World!\n";
  C obj = f();
}

Depending upon the compiler, and that compiler's settings, the resulting program may display any of the following outputs:

Hello World!
A copy was made.
A copy was made.

Hello World!
A copy was made.

Hello World!

Background

Returning an object of builtin type from a function usually carries little to no overhead, since the object typically fits in a CPU register. Returning a larger object of class type may require more expensive copying from one memory location to another. To achieve this, an implementation may create a hidden object in the caller's stack frame, and pass the address of this object to the function. The function's return value is then copied into the hidden object.[5] Thus, code such as this:

struct Data {
  char bytes[16];
};

Data f() {
  Data result = {};
  // generate result
  return result;
}

int main() {
  Data d = f();
}

May generate code equivalent to this:

struct Data {
  char bytes[16];
};

Data * f(Data * _hiddenAddress) {
  Data result = {};
  // copy result into hidden object
  *_hiddenAddress = result;
  return _hiddenAddress;
}

int main() {
  Data _hidden; // create hidden object
  Data d = *f(&_hidden); // copy the result into d
}

which causes the Data object to be copied twice.

In the early stages of the evolution of C++, the language's inability to efficiently return an object of class type from a function was considered a weakness.[6] Around 1991, Walter Bright invented a technique to minimize copying, effectively replacing the hidden object and the named object inside the function with the object used to hold the result:[7]

struct Data {
  char bytes[16];
};

void f(Data *p) {
  // generate result directly in *p
}

int main() {
  Data d;
  f(&d);
}

Bright implemented this optimization in his Zortech C++ compiler.[6] This particular technique was later coined "Named return value optimization", referring to the fact that the copying of a named object is elided.[7]
[edit] Compiler support

Return value optimization is supported on most compilers.[1][8][9] There may be, however, circumstances where the compiler is unable to perform the optimization. One common case is when a function may return different named objects depending on the path of execution:[5][8][10]

#include <string>
std::string f(bool cond = false) {
  std::string first("first");
  std::string second("second");
  // the function may return one of two named objects
  // depending on its argument. RVO might not be applied
  return cond ? first : second;
}

int main() {
  std::string result = f();
}

No comments:

Post a Comment