|
| |
June 2nd, 2008
The following code snipped gives an error when compiling it with VC6, although it’s legal according to the C++ standart.
SomeFunction ()
{
for (int i =0; i<5; i++)
{ ... }
for (int i =0; i<10;i++)
{ ... }
}
Previously, the definition would be considered occurring outside of the braces, and would be in scope until the end of the outer enclosing braces (until the end of SomeFuncion() in the example above), so defining i in the second for loop gives a redefinition error.
Under the new rules, the variable definition is considered occurring inside the braces of the for() loop, and it goes out of scope at the end of the for loop, so both variable definitions given above would be needed.
It gives an error on the second for () complaining about i being redefined.
- In VC7 (2002), the compiler was changed so that both conforming and
non-conforming code was accepted, but neither interpretation was enforced -
you could freely mix.
- In VC 7.1 (2003), the
/Zc:forScope option was introduced and was by-default
turned off, preserving the VC7 (and earlier) behavior.
- In VC8 (2005), the default was changed so that the option is on by default.
- VC9 (2008) changes nothing with regard to for-loop variable scoping.
So, what do you do if you need the new scooping rules?
A tumb rule is that you can turn it off, and get the VC6 behavior, by adding /Zc:forScope- to
your compiler options in the project properties dialog.
The following macro has been suggested as a workaround:
#define for if (0) {} else for
However, using a macro to change the semantics of a program is generally not a good idea, and should only be used in extreme cases, such as when trying to compile code developed under a compiler that implements the new rule. Applying the macro to code developed under the original rule can result in silent behavioral changes, as described above. A compiler that implements the new rule can warn about code whose interpretation differs under the old and new rules, so it’s best to wait for proper compiler support, if you can.
Another way you can go is to use the preprocessor macro MSC_VER and create conditional compilation blocks, or simply define the varibable outside of the first loop and set initialize it every time again.
Yet another workaround is to enclose each for() sentence in braces, like this:
{
for ( int i = 0; i < 10; i++ )
{
// ...
}
}
{
for ( int i = 0; i < 12; i++ )
{
// ...
}
}
This effectively creates yet another scope that hides the for-loop scooping bug. However, it adds unnecessary scopes and is easy to forget to close one of them or them alltogether.
May 22nd, 2008
Algorithms can often be implemented recursively or nonrecursively; the decision rests with the programmer, who might shy away from a recursive solution because the algorithm might not terminate or that performance might be poor. In reality, recursion can allow for very elegant code as well as facilitating an interesting and economical type of code reuse.
Iterative algorithms, especially those with a loop, can usually be easily rewritten to use recursive function calls instead of loops. In some cases it’s a bad idea because the iterative version is usually simpler, faster, and uses less memory.
The classical scenario for recursion was search algorithms, factorial calculations, and so on. A well-know algorithmn that uses recursion is Binary Search.
This recursive version checks to see if we’re at the key (in which case it can return), otherwise it calls itself so solve a smaller problem, ie, either the upper or lower half of the array.
int BinarySearch(int iSortedArray[], int iFirst, int iLast, int iKey)
{
if (iFirst <= iLast) {
int iMid = (iFirst + iLast) / 2;
if (iKey == iSortedArray[iMid])
return iMid;
else if (iKey < iSortedArray[iMid])
return BinarySearch(iSortedArray, iFirst, iMid-1, iKey);
else
return BinarySearch(iSortedArray, iMid+1, iLast, iKey);
}
return -(iFirst+ 1); // failed to find key
}
Besides elegant code design recursion can be the reason for some problems.
Recursion isn’t safe in C/C++ because there is no reasonable way to deal with running out of call stack space. Even if you dynamically allocate stack frames from the heap, you still can run out of heap and how do you handle the error then?
You might convert the failed call stack allocation into an exception that unwinds the stack until an out-of-stack exception handler is found, but the problem is that any function in any library called from a recursive routine might be the call that blows the stack.
Fortunately any algorithm that can be written recursively can be rewritten iteratively by keeping a heap-based stack object (and if it can be written completely tail-recursively, you don’t even need a stack). The code might be uglier when written iteratively, but it’s always possible.
You’d defenetly use recusion when you can guarantee two things:
- Each recursive step breaks down the problem into a smaller problem of the same type.
- Each recursive step reduces the problem significantly.
The first is a general rule of recursion. If each step doesn’t break the problem down into a smaller problem of the same type, it’s harder to write a recursive function and guarantee that it will terminate. The second is kinda personal guideline. I generally won’t write a recursive function unless it divides the problem in half with each step. This way I can verify with relative ease that the algorithm will be efficient.
Originally I planted to write this post about anonymous recursion with lambda in c#, but then I decited to describe recursion basics a bit more in detail.
A simple recursive function in c# would be for example:
private static double pow(double var, double n)
{
if(n == 0)
return 1;
else
return var * pow(var, n - 1);
}
Anonymous recursion is a recursion technique that uses anonymous functions.
I got the idea to define a special delegate type for self-applicable functions:
delegate T Pow<T>(Pow<T> self);
The delegate above can be defined like this:
Pow<double> myPow = f => f(f);
myPow(myPow);
When myPow is being applied to itselfwill apply myPow to itself, which will ⦠infinite recursion. While not particularly useful in this setting, the example demonstrates that you can in fact have recursive application in a lambda expression. Now all we have to do is to make it do something useful as it goes, such as call functions recursively.
Recursion is beautiful and lambdas are the ultimate abstraction. But that’s too much for now…I’ll write about that sometime.
May 5th, 2008
Often includes from the standard library conflicts with the MFC library. Microsoft can’t do anything about it because of backward compatibility. The conflict are the functions min() and max(). The only thing that is done is to check for a preprocessor value NOMINMAX. If you define this for the whole project, conflicts should be avoided.
It is done in the Project | Settings, and the tab C/C++. Add the NOMINMAX definition to the “Preprocessor definitions” area.
The problem is caused by conflicting definitions of min and max. Min and max are defined as macros in Windef.h as follows:
#ifndef NOMINMAX
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#endif /* NOMINMAX */
April 18th, 2008
If it’s wanted to match a string against a pattern based on wild characters (* and ?). The function presented here is a simple one that does this matching.
Patterns can be:
- bka-b*
- bk*bonn
- bka-bo?n
- b*b?nn
This is a fast, lightweight, and simple pattern matching function.
The function has to be call the function with two arguments. The first one is the string to be compared with the pattern specified in the second arguments.
The return value is accoring to the state if I should match Exact, Any or AnyRepeat.
bool MatchPattern(const char* szCompare, const char* szPattern)
{
enum State
{
Exact, // exact match
Any, // ?
AnyRepeat // *
};
const char* szTmp = szCompare;
const char* szPat = szPattern;
const char* q = 0;
int iState = 0;
bool bMatch = true;
while (bMatch && *szPat)
{
if (*szPat == '*')
{
iState = AnyRepeat;
q = szPat+1;
}
else if (*szPat == '?')
iState = Any;
else
iState = Exact;
if (*szTmp == 0)
break;
switch (iState)
{
case Exact:
bMatch = *szTmp == *szPat;
szTmp++;
szPat++;
break;
case Any:
bMatch = true;
szTmp++;
szPat++;
break;
case AnyRepeat:
bMatch = true;
szTmp++;
if (*szTmp == *szPat)
szPat++;
break;
}
}
if (iState == AnyRepeat)
return (*szTmp == *szPat);
else if (iState == Any)
return (*szTmp == *pszPat);
else
return bMatch && (*szTmp == *pszPat);
}
Obviously usage is as expected:
if(MatchPattern("bka-bonn", "b*b?nn"))
{
//matches
}
else
{
//no match
}
Finally I have to tell you that function doesn’t perform any error checking.
For matching patterns you also can use regular expressions - a good regex c++ library is provided by boost.
Simple example for it’s usage:
boost::regex expr("abcd[a-z].*");
string line("bka-bonn");
if (boost::regex_search(line, expr))
{
//matches
}
else
{
//no match
}
Further information can be read in boost’s docs: Boost.Regex
Indeed regular expressions are much more flexible and powerful but if you just want to match with ? and * wild characters the above mentioned function might be a better solution.
As always you also here have to weigh one thing against another. You might wonder what is important performance or flexibility.
If you just need it at one certain point in your project and it will never be enhanced I’d choose the MatchPattern function cause it’s simple and you don’t have to use an external library.
Otherwise, if a lot of lines in your code are based on matching strings, boost’s regex library should be the recommented way.
April 11th, 2008
Namespace definitions hold declarations. Since a namespace definition is a declaration itself, namespace definitions can be nested.
An alias can also be applied to a nested namespace.
namespace INTERNATIONAL_BUSINESS_MACHINES {
int j;
namespace NESTED_IBM_PRODUCT {
void a() { j++; }
int j;
void b() { j++; }
}
}
namespace NIBM = INTERNATIONAL_BUSINESS_MACHINES::NESTED_IBM_PRODUCT
In this example, the NIBM identifier is an alias for the namespace NESTED_IBM_PRODUCT. This namespace is nested within the INTERNATIONAL_BUSINESS_MACHINES namespace.
April 3rd, 2008
I have been irritated many times when IntelliSense stoped working immediately in the middle of programming. Sometimes the whole IntelliSense quits and at other times only certain sections of code fails to bring up List Members and Parameter Info.
According to Microsoft if there is an incomplete function or other coding error above the location of the insertion point, IntelliSense may be unable to parse the code elements and therefore will not work. It’s recommented to comment out the applicable code to enable IntelliSense again.
—
I found out that certain lines in my code bring IntelliSense to a stand-still.
Any code in Visual Studio that uses a comma-list to define an array of object constructor parameters will kill IntelliSense for all code following the definition.
This works well:
int iSomeNumbers[] = {4, 14, 1, 44 ,1};
char cWord[] = "test";
’cause it’s just a simple array.
The problem appears when using array definitions that include object constructors to create elements.
IntelliSense gets confused by this and crashes:
Point arPoints[] = {Point(1,4), Point(4,1), Point(4,1), Point(4,1)};
The easiest workaround to keep IntelliSense keep on working proper is to this kinda long winded way:
Point arPoints[4];
arPoints[0] = Point(1,4);
arPoints[1] = Point(4,1);
arPoints[2] = Point(4,1);
arPoints[3] = Point(4,1);
At least I discoverd in the web that this line messes up IntelliSense:
Point arPoints[] = {Point(1,4), Point(4,1), Point(4,1), Point(4,1)};
This one does not:
Point[] arPoints= {Point(1,4), Point(4,1), Point(4,1), Point(4,1)};
Notice that the array brackets are after the type not the identifier.
—
Hopefully someone can help determine other situations that cause IntelliSense to fail.
|
| |