Description : Hide Function Pointer Declarations With a typedef
Can you tell what the following declaration means?
void (*p[10]) (void (*)() ); Only few programmers can tell that p is an "array of 10 pointers to a function returning void and taking a pointer to another function that returns void and takes no arguments." The cumbersome syntax is nearly indecipherable. However, you can simplify it considerably by using typedef declarations. First, declare a typedef for "pointer to a function returning void and taking no arguments" as follows:
typedef void (*pfv)(); Next, declare another typedef for "pointer to a function returning void and taking a pfv" based on the typedef we previously declared:
typedef void (*pf_taking_pfv) (pfv); Now that we have created the pf_taking_pfv typedef as a synonym for the unwieldy "pointer to a function returning void and taking a pfv", declaring an array of 10 such pointers is a breeze:
pf_taking_pfv p[10]; Danny Kalev
2.) Algorithm that you will mesmerize Source - http://www.devx.com/tips/Tip/39012 Desc : Finding Modulus of a Very Large Number with a Normal Number I recently encountered this problem in a C++ program running on a 32-bit UNIX platform. The problem was that the number was 28 digits long and no native datatype in C++ could store a number of that sizenot even unsigned long long or long double could help; they were only eight bytes long. A divide-and-conquer strategy can be used in this casethe entire number doesn't have to be processed in one go. Divide the number into smaller numbers, then find the remainders of these smaller numbers. Add up the remainders and repeat the process. As long as the remainders are retained, the final answer wont change. Suppose you need to find nBig % a: 1. Take a manageable portion (say, x) of the input large number (nBig) and subtract it from nBig (nBig = nBig - x). 2. Compute the mod of x (mod = x % a). 3. Add the mod to nBig (nBig = nBig + mod). This way, the number nBig can be reduced without affecting the actual answer. This first example uses small numbers, so it's easy to follow the logic. To find 27 % 8: 1. Let x = 17. Thus, nBig = nBig - x = 27-17 = 10. 2. mod = x % a = 17 % 8 = 1 3. nBig = nBig + mod = 10 + 1 = 11 4. Thus, nBig is reduced from 27 to 11 without affecting the answer, which is 3. But what about finding the mod of large numbers? Extend the same logic, and the above problem can be solved as follows: 1. Let the input be: o nBig: This is a string representing a 30 digit large number (for example, 123456789033333333335555555555) o a: Integer (for example, 320) 2. To find nBig % a: 1. Iteration 1: 1. Extract few digits from the LHS of nBig. Thus, tmp = 1234567890 and nBig = 33333333335555555555. 2. Find mod of tmp: 3. 4. mod = tmp % a = 210 5. Prefix mod to nBig: 6. 7. nBig = 21033333333335555555555 2. Iteration 2: 1. tmp = 2103333333 and nBig = 3335555555555 2. mod = tmp % a = 213 3. nBig = 2133335555555555 3. Iteration 3: 1. tmp = 2133335555 and nBig = 555555 2. mod = tmp % a = 195 3. nBig = 195555555 4. Iteration 4: 1. tmp = 195555555 and nBig = "" 2. mod = tmp % a = 35 5. The Answer = 35. What follows is the pseudo code for finding nBig % a. First, let d = the number of digits that can be processed at a time. Then, repeat while val( nBig ) >= a. 1. tmpStr: Equals d digits from the LHS of nBig. 2. nBig: Equals the remaining portion of nBig. 3. tmpNum: Equals toInteger(tmpStr). 4. tmpNum: Equals tmpNum % a. 5. tmpStr: Equals toString(tmpNum). 6. nBig: Equals tmpStr + nBig. To select d, make sure d satisfies the following constraint: The maximum number of digits in Mod a < d < should equal the maximum tmpNum minus the maximum number of digits in Mod. For example, suppose you have a = 512 (Mod ranges 0..511), and your tmpNum can store a maximum of 16 digits. Then, you'd have:
3 < d <= 16-3) In another example, suppose a = 100 (Mod ranges 0..99), and tmpNum can store a maximum of 16 digits. In that case, you'd have:
2 < d <= 16-2) Sameer Palande 3.) source - http://www.devx.com/tips/Tip/28817 Description Retrieving Only Unique Elements from Two Sets
This algorithm helps you to retrieve all the elements contained in the first set (set1), but not in the second (set2). Here's the template:
template<class T> void Diff(const T& set1, const T& set2, T& res) { T temp; typename T::const_iterator it = set1.begin(); if (&set1 == &set2) return; else { while (it != set1.end()) { if (set2.find(*it) == set2.end()) // element not found temp.insert(*it); ++i; } } temp.swap(result); } Mykola Rozhok 4.) Source - http://www.devx.com/tips/Tip/17121 Description Use the Count Algorithm to Perform Simple Validation on Strings Sometimes it's necessary to perform a simple validation on a string to ensure, for example, that a string destined to be converted to a float contains only a single '.'. If only simple validation of some kind is required, it's trivial to use the count algorithm to tally up suspected chars and report their numbers, as in:
string n = "joebob@bigtrucks@com"; string d = "12.34";
int A = count(n.begin(), n.end(), '@'); int C = count(d.begin(), d.end(), '.');
cout << "There are " << A << " @ signs in JoeBob's email address!" << endl; cout << "There's " << C << " decimal point in JoeBob's checking balance." << endl;
return 0; } It's nice to remember that strings are containers in the STL, just like a vector or list, and that their iterators refer to char pointers that can be counted, sorted, or partitioned just like any other collection of values. Greg McClure 5.) Source - http://www.devx.com/tips/Tip/13879 Description: The reverse() Algorithm Another useful STL algorithm is reverse(). This algorithm reverses the order of elements in a specified sequence. reverse() takes two iterators that mark the sequence's beginning and end, respectively. Here is an example of reversing the order of a char array:
#include <algorithm> #include <vector> using namespace std; int main() { char arr[4] = {'a','b','c','d'}; reverse(arr, arr+4); // arr is now "dcba" } Remember that the second argument of reverse() must point one element past the array's bounds. Here's an example of applying reverse() to a vector object:
int main() { char arr[]= {'a','b','c','d'}; vector <char> vc (arr, arr+4); // initialize vc reverse(vc.begin(), vc.end()); } Danny Kalev 6.) Source http://www.devx.com/tips/Tip/14446 Description: Casting To and From void* In C++, pointers are strongly-typed. Therefore, you can't assign a void pointer to any other pointer type without casting it explicitly:
int n; void *p = &n; int *pi=static_cast< int* >(p);//C++ requires explicit cast
In C, the explicit typecasting is not required. By contrast, you can assign any data pointer to void* without casting:
string s; void *p=&s; // no cast required here Danny Kalev 7.) Source- http://www.devx.com/tips/Tip/14443 Description: C++ Null Pointers and Delete C++ guarantees that operator delete checks its argument for null-ness. If the argument is 0, the delete expression has no effect. In other words, deleting a null pointer is a safe (yet useless) operation. There is no need to check the pointer for null-ness before passing it to delete:
if (p) // useless; delete already checks for a null value delete(p); Danny Kalev 8.) Source - http://www.devx.com/tips/Tip/14323 Description: Invoking a Function Through a Pointer When you call a function through a pointer to function, use that pointer as if it were the function itself, not a pointer. For example:
#include <cstring> char buff[10]; void (*pf) (char *, const char *); pf = strcpy; // take address of strcpy pf(buff, "hi"); // use pf as if it were the function itself Danny Kalev 9.) Source - http://www.devx.com/tips/Tip/26434 Description: Checking If a Function Pointer is Valid Question: I am collecting a number of function pointers in C++ and before I call them I want to check to see if they have been set. I really want to avoid calling them if they aren't valid. I have tried the following "if func != Null { ... " but I get an error. Answer: First of all, there's no 'Null' in C++. The constant NULL is all uppercase. However, it's not a keyword so you have to #include a header file to make its definition visible to the compiler. The best way check for nullness is to compare the pointer (any type of pointer, including a pointer to member) to the literal zero: if (pmf!=0) DevX Pro 10.) Source - http://www.devx.com/tips/Tip/14104 Description: Assigning a Specified Memory Address to a Pointer In low-level programming and hardware interfaces, you often need to assign a pointer to a specific physical address. To do that, you have to cast the address value using the reinterpret_cast operator. Here's an example that shows how this is done:
void *p; // assign address 0x5800FF to p p = reinterpret_cast< void* > (0x5800FF); Danny Kalev 11.) Source - http://www.devx.com/tips/Tip/25948 Description: OS System Calls Question: How can I pass a member function of a class as a pointer in C (pointer type expected: void *)? Answer: You can't pass a pointer to a C++ class member as void *. A pointer to member is not really a pointer, it's a data structure. One way to get around this is to declare the member function static. A pointer to a static member function actually is a pointer to an ordinary function. For example: caller(void * a_ptr); //your caller func typedef void * (*PF)();
class A { public: static void* func(); //callback member function };
int main() { PF pf; pf = &A::func; // pf is a pointer to function caller(pf); }
caller(void * a_ptr) { PF ptr = (PF) a_ptr; void * val = ptr();//call member function } DevX Pro 12.) Source - http://www.devx.com/tips/Tip/25707 Description: - Assign Zero or NULL to a Pointer Question: To initialize a pointer after deleting it, should I assign a NULL to it or zero? Are they the same in C++? I know strictly speaking, I should assign NULLs to deleted pointers. But the app I work with uses zeros instead. I wonder if I need to change them. Answer: C and C++ define NULL differently. A typical definition of NULL in C++ looks like this: #define NULL 0 Whereas in C, NULL is usually defined like this: #define NULL ((void*)0) Why is this? Pointers in C++ are strongly-typed, unlike pointers in C. Thus, void* cannot be implicitly converted to any other pointer type without a cast operation. If C++ retained C's convention, a C++ statement such as: char * p = NULL; would be expanded into: /*error: incompatible pointer types*/ char * p = (void*) 0; For this reason, the C++ standard requires that NULL be defined either as 0 or as 0L. In other words, NULL is just an alias for the literal zero. Therefore, you may use zero as a pointer initializer directly. There's no need to replace 0 with NULL. DevX Pro 13.) Source - http://www.devx.com/tips/Tip/25592 Description: - Pointer to Structure Question: I have a struct: struct mystruct { DWORD dw_Id; }*pMystruct; In the following function I want to pass the address of 'dw_Id' which is a member of mystruct. How do I pass it? If I am passing as- foo(pMystruct->(&dw_Id))//compiler error Answer: You pass the address of a pMyStruct member like this: foo( &pMystruct->dw_Id); Make sure that pMyStruct points to an instance of Mystruct. DevX Pro 14.) Source: http://www.devx.com/tips/Tip/13676 Description: Iterators Aren't Pointers Suppose you define a the following list object and you need the address of one of its elements:
std::list <int> li; std::list <int>::iterator iter = li.begin(); In many contexts, iter functions like a pointer. However, when you need a real pointer to a container's element, you can't use an iterator:
int func(int * p); int main() { func(iter); // error, iter is not a pointer to int } The problem is that in general, iterators aren't pointers. Rather, they are usually implemented as objects. To get a pointer to the element an iterator refers to, you need to "dereference" that iterator and take the address of the result. For example:
int main() { func( &*iter); // ok } Danny Kalev 15.) Source - http://www.devx.com/tips/Tip/25486 Description: Pointer Arithmetic Question: I am a programmer beginning to learn C++. I wrote this chunk of code: ///////////////////////////////////////////////////////////// // Get to do some pointer arithmetic! /////////////////////////////////////////////////////////////
void main() { char *str = "This is a wild test string..."; char *ch = &str[0];
for (unsigned i=0;i<< *ch++;
cout << NL << ReverseString(str); }
char *ReverseString(char *pStr) { int len = strlen(pStr); char *f = &(pStr[0]); char *b = &(pStr[len-1]); char temp;
// swap from forward to backward do { temp = *f; *f = *b; *b = temp;
++f; --b; }while (f < b);
return pStr;
} //////////// End of Code ////////////////////////////////// This code compiles without any error warnings. However, when I execute the code, the program crashes with an Access Violation error. In debugging I found that the offending line is in the ReverseString function, and I encounter the Access Violation error at the following statement: *f = *b; I compiled the same program in C++ Builder 3.0. The program compiled successfully, and on execution it worked perfectly fine. So, the problem lies with Visual C++ 6.0 compiler. Let me provide the system configuration. Platform: Intel Operating System: Windows 2000 RC2 Development Environment: Visual C++ 6.0 Enterprise Edition SP3 Why is this error happening? Answer: Your reverse() function attempts to modify a const array of chars, which is a disallowed operation. Remember that every string literal is a constant, and so is str in this statement: char *str = "This is a wild test string..."; First, never use plain char * when pointing to a literal string. Use const char * instead: const char *str = "This is a wild test string..."; Now if you try to compile the const version, your compiler will flag the reverse() call in main() as an error. What you should do is use an array of char rather than a pointer: char str[] = "This is a wild test string..."; This should be OK. DevX Pro 16.) Source - http://www.devx.com/tips/Tip/25671 Description:- Possibility of Decompiling an EXE File? Question: How can I get the source code from EXE files? Does it matter if they are read-only? Answer: This question is asked very frequently. However, the answer is always the same: there's no way you can decompile an executable and restore the original source file. The longer answer will also convince you why trying to find such a tool is at least as futile as trying to find the Holy Grail. First, remember that there is no 1:1 relation between a piece of assembly code and a corresponding source code written in a high-level language such as C++. For example, for loops, switch statements, and while blocks, are all translated into the same assembly directives. In other words, there is an infinite number of C++ programs that can produce the exact assembly code. The same is true for other language constructs, which are translated into a single assembly entity: pointers, references, and arrays, for example. Furthermore, each compiler produces a different executable for a given source file. Even if you know the exact compiler brand that was used for compiling the program, as well as its version number, how can you tell which compile-time options were used during compilation? Also, how can a decompiler reconstitute macros, inline functions, and typedef's when all these are all substituted before the compiler actually translates the source code into machine code? Remember also that normally the debugging information is removed from the executable so that the decompiler will not be able to reconstitute the original names of variables, classes, arrays, pointers, functions, and constants. To conclude, developing a utility that decompiles an executable file into its original C++ source code (or anything that comes close to the original) is unrealistic. That also answers the second questionit doesn't really matter whether the files are read-only; it's simply impossible. DevX Pro 17.) Source - http://www.devx.com/tips/Tip/25055 Description - Constant Pointer Question: Can you expalin the difference between the following statements in some examples and when do we need them:
const char *ptr; // char *const ptr; // Answer: The following statement:
const char *ptr; defines a pointer to a const char array. This means that the pointer itself can change its value (e.g., you can do something like ptr++ or ptr--, as well as assign a new value to ptr). However, you cannot change the characters in the array to which ptr points. Thus ptr[0] = 'a' is illegal. On the other hand,
char *const ptr; declares a const pinter to a non const char array. You can change the characters in the array through the const pointer: ptr[0] = 'a';//OK but you cannot change the pointer itself: ptr++, ptr-- and assigning a new value to ptr are all illegal. You need the first form to disable undesirbale changes to the string, such as when you pass it to another function that is not allowed to modify it. The second form is rarer. It is used when the pointer is mapped to a hardware port, for example. DevX Pro 18.) Source - http://www.devx.com/tips/Tip/13358 Description Passing More Arguments to a Callback Function Callback functions have a fixed signature so you cannot alter the number or type of the arguments it takes. For example, the standard qsort() function takes a pointer to a function that has the following signature:
int (cmp*)(const void *, const void *) //user's comparison function This signature allows you to pass exactly two arguments to your custom-made comparison function. However, suppose that the comparison function has to compare strings and you want to pass a third argument to indicate whether the comparison should be case-sensitive or not. You cannot simply add a third argument to the function call, because the compiler will complain about it (don't even think about casting the function pointer; see this tip). Instead, you can define a struct that contains two members:
struct Comparison { char *name; bool caseSensitive; }; Now instead of passing a pointer to char as the second argument, you can pass a pointer to an instance of that struct. The comparison function will unpack the struct and compare the strings accordingly:
int MyCompareFunc(const void *pfirst, const void * psecond) { const Comparison * pcmp = (Comparison *) psecond; const char * pstr1 = (const char *) pfirst; const char * pstr2 = pcmp->name; //extract string from struct if (pcmp->caseSensitive == true) //the second field of the struct { return strcmp(pstr1, pstr2) } else { //perform case-insensitive comparison } } Danny Kalev 19.) Source - http://www.devx.com/tips/Tip/24996 Description Functions Returning Arrays Question: Is it possible for a function to return an array instead of a single value? Answer: No but, then again, you don't really pass arrays as parameters, either. What C/C++ can do is pass the address of an array (a pointer) and you can return a pointer, too. Just be careful that when you return a pointer to an array, that the array is properly allocated. For example, if you create an array within your function:
int *MyFunc() { int a[20]; return a; } this will fail because local variables are allocated on the stack and will no longer be valid when the function returns. DevX Pro 20.) Source - http://www.devx.com/tips/Tip/12683 Description Member Alignment Manual calculation of a struct/class size is not just an indication of poor design and a source of maintenance problems; it may also lead to bugs that are very hard to detect:
struct Person{ char firstName[5]; char lastName[8] }; //the actual size of Person is most likely larger than 13 bytes Person p= {{"john"}, {"lippman"}}; memset(&p, 0, 5+8 /* surprise */ ); //not all members of p are completely erased! Simple addition of the sizes of each data member in a struct/class will probably yield a wrong size. Wrong sizes occur because the compiler is allowed to add additional padding bytes between members whose size does not fit exactly into a machine word. Padding enables programs to execute significantly faster (especially on RISC machines). On a 32 bit (four bytes) processor, three additional bytes will be inserted between the two members of Person, thus making the first member occupy eight bytes--a size that fits neatly into two processor's words. In our case, it also means that Person's size is 16 bytes and not 13. (You should consult your compiler's manual in order to find out what its default alignment is). Consequently, on some implementations, the above memset function will leave the last three bytes of p.lastName uninitialized. Therefore, the size of a struct/class should always be calculated by the sizeof operator:
memset(&p, 0, sizeof(Person)); //correct Danny Kalev 21.) Source - http://www.devx.com/tips/Tip/12607 Description Pre-Defined Macros All C/C++ compilers define the following macros:
__DATE__ //a literal containing the compilation date in the form "Apr 13 1998" __TIME__ //a literal containing the compilation time in the form "10:01:07" __FILE__ //a literal containing the name of the source file being compiled __LINE__ //a decimal integer containing the current line number in the source file In addition, a C++ compiler defines the following macro:
__cplusplus //useful for combining legacy C code with C++ And an ANSI conforming C compiler defines the following macro:
__STDC__ //useful when one has to test whether the current compiler is ANSI C compatible These macros can be useful for debugging and issuing diagnostic messages:
if(isSuccessful == false) { printf("failed to open transaction; error occurred at line %d in file %s", __LINE__,__FILE__); } Danny Kalev 22.) Source - http://www.devx.com/tips/Tip/28735 Description When to Pass Parameters by Value The main reason to pass parameters by value is to improve performance, which is somewhat of a paradox, because this is also one of the main reasons to pass by reference. The truth is that either method can improve performanceit just depends on the situation. Passing a parameter by reference avoids copying all the data members onto the stack, which could take a lot of resources if you've got a lot of members or you're going to be calling the recipient function frequently. It also saves the time and memory required to allocated pointer members; allocating on the heap is much slower than pushing onto the heap. If the parameter being passed is small, it's possible that the compiler will place the entire value in a register for its whole lifetime. This is especially the case for built-in types or classes that contain one or two members that are also built-in types. If you pass a register variable by value, depending on the processor and the compiler, the parameter may be passed in a register, which is very fast. If you pass it by reference, the compiler will have to store the object in RAM so that its address may be takenreferences are usually implemented as RAM addresses. Essentially they are pointers that are automatically dereferenced for you, although I don't think the ISO standard requires they be implemented in any particular way. Suppose an object could have been stored in a register, and you pass it as a reference or pointer. This causes the compiler to copy the register to the stack, pass the stack address, and then possibly copy it back into a register after the call. This definitely slows you down. Again, this is only permissible if slicing is not a problem. The recipient function expects the exact same type as the type you are passingnot its base class. This is often the case for simple classes like geometric points or numerical values. If the copy constructor for the class you are passing is inlined, it may be faster to pass it by value. Wael Salman 23.) Source - http://www.devx.com/tips/Tip/14639 Description - How to Choose the Right Data Structure Following are some tips for matching the most commonly used data structures with particular needs. 1. When to use a Hashtable? A hashtable, or similar data structures, are good candidates if the stored data is to be accessed in the form of key-value pairs. For instance, if you were fetching the name of an employee, the result can be returned in the form of a hashtable as a (name, value) pair. However, if you were to return names of multiple employees, returning a hashtable directly would not be a good idea. Remember that the keys have to be unique or your previous value(s) will get overwritten. 2. When to use a List or Vector? This is a good option when you desire sequential or even random access. Also, if data size is unknown initially, and/or is going to grow dynamically, it would be appropriate to use a List or Vector. For instance, to store the results of a JDBC ResultSet, you can use the java.util.LinkedList. Whereas, if you are looking for a resizable array, use the java.util.ArrayList class. 3. When to use Arrays? Never underestimate arrays. Most of the time, when we have to use a list of objects, we tend to think about using vectors or lists. However, if the size of collection is already known and is not going to change, an array can be considered as the potential data structure. It's faster to access elements of an array than a vector or a list. That's obvious, because all you need is an index. There's no overhead of an additional get method call. 4.Combinations Sometimes, it may be best to use a combination of the above approaches. For example, you could use a list of hashtables to suit a particular need. 4. Set Classes
And from JDK 1.2 onwards, you also have set classes like java.util.TreeSet, which is useful for sorted sets that do not have duplicates. One of the best things about these classes is they all abide by certain interface so that you don't really have to worry about the specifics. For e.g., take a look at the following code.
// ... List list = new ArrayList(); list.add( Shantanu Garg 24.) Source - http://www.devx.com/tips/Tip/14337 Description Don't Use const for Passing Parameters by Value To avoid undesirable changes to an argument passed by reference, you pass it as a const parameter. For example:
void f(const string & s); // f can't change s However, some programmers use const even when they pass parameters by value, for example:
void f(const int n); // n is passed by value, why const? Is it really necessary? No, it's not. Remember that when you pass a parameter by value, the function called can't make changes to original value anyway because it receives a copy of it. Therefore, the use of const for passing parameters by value only blocks the function from changing its local copy. However, whether a function changes its local copy of some variable is an implementation detail; it's not a part of the interface. Therefore, users of this function don't (and shouldn't) need to know that. As a rule, don't declare parameters const if they are passed or returned by value. Danny Kalev 25.) Source - http://www.devx.com/tips/Tip/20915 Description Identifying Memory Leaks in Linux for C++ Programs Most C++ programmers agree that it can be harrowing trying to identify the memory leaks in a given program. If you're working on the GNU/Linux platform, there's an interesting tool you can use to minimize the hassle of this task: mtrace. Here's some background on mtrace: 1. You call the mtrace() function to log all memory leaks. The memory allocations and deallocations are logged to a text file pointed to by the environment variable MALLOC_TRACE. 2. A Perl utility called mtrace parses the text file logged by your program and identifies the memory leaks. The following code allocates memory, but does not essentially free it:
#include <stdlib.h>
int main() { int *a;
a = malloc(sizeof(int)); //Allocate memory
*a = 7; //Notice that we are not freeing memory before we end the program.
return EXIT_SUCCESS; } Now, see how to use mtrace to identify the memory leak: Step 1: Setup MALLOC_TRACE environment variable to point to a file where mtrace needs to log the memory allocations:
setenv MALLOC_TRACE /home/karthik/temp/trace.txt Step 2: Insert mtrace hooks into the program:
#include <stdlib.h> #include <mcheck.h> /* Header file to include mtrace related functions */
int main() { int *a;
mtrace(); /* This starts memory tracing. This has to be done before we do a 'malloc' or we allocate memory. */
a = malloc(sizeof(int)); /* Allocate memory */
*a = 7; /* Notice that we are not freeing memory before we end the program. */
return EXIT_SUCCESS; } Step 3: Compile the modified program with the debugging options turned on:
$ gcc -g -Wall -ansi -pedantic leak.c Step 4: Run the program. Step 5: Use the mtrace utility to retrieve the information. Here's what the syntax looks like:
Memory not freed: ----------------- Address Size Caller 0x08049910 0x4 at /home/karthik/tips/leak.c:9 This precisely tells you that there is a potential memory leak at line 9:
a = malloc(sizeof(int)); /* Allocate memory */ mtrace is a GNU utility. The code in this tip was tested on a Linux platform with the gcc 3.2.3. Karthik Kumar Arun Kumar 26.) Source - http://www.devx.com/tips/Tip/13747 Description - When Is It Safe to Use Inline? Excessive use of inline functions might bloat the size of the executable and reduce execution speed. In other words, using inline abundantly can degrade rather than enhance performance. For this reason, many programmers avoid function inlining altogether because they can't predict how inlining will affect performance. However, there is one guarantee: very short functions (e.g., a function that merely calls another function or a function that returns a data member of its object) are always good candidates for inlining. For example:
inline bool Foo::is_connection_alive() { return ::connection_alive(); // calls an API function } inline int Bar::get_x() { return x; // merely returns a data member } By inlining such functions, the size of the executable decreases slightly and execution speed is boosted. Note, however, that this rule applies to very short functions exclusively. For larger functions, you usually need to profile the software with and without inline to assess the effects of inlining. Danny Kalev