Posts

Showing posts from February, 2006

testing memory failure allocation

there is a difference of how the memorey failure is handled in C++. int *pa = new int[10000]; in the article " The new and delete Operators" the MSDN says: "Beginning in Visual C++ .NET 2002, the CRT's new function (in libc.lib, libcd.lib, libcmt.lib, libcmtd.lib, msvcrt.lib, and msvcrtd.lib) will continue to return NULL if memory allocation fails. However, the new function in the Standard C++ Library (in libcp.lib, libcpd.lib, libcpmt.lib, libcpmtd.lib, msvcprt.lib, and msvcprtd.lib) will support the behavior specified in the C++ standard, which is to throw a std::bad_alloc exception if the memory allocation fails." hence is vital to know which one you are using. "Normally, if you #include one of the C++ standard headers, like , you'll get a /defaultlib directive in your object that will reference the appropriate C++ Standard Library according to the CRT model you used (the /M* compiler options). Generally, that will cause the linker to use the throwin...

remember the rule

sometimes its hard to figure out which method is called when looking at a hierarchy of classes, which use virtual specifier for their methods. but, as always, if you know how the things works internally, you will always find the right answer. I always think that instead of remembering 10 specific cases (which it might not be hard at all for many people, but me for example, I have a bad memory) its much easier to remember 1 thing only, how it works. this is a case for the virtual specifier. the thumb rule is this (this is from MSDN): When calling a function using pointers or references, the following rules apply: 1.A call to a virtual function is resolved according to the underlying type of object for which it is called. 2.A call to a nonvirtual function is resolved according to the type of the pointer or reference. but this rule might not be always simple to apply. What is really good is to know why the things are happing like described in those 2 rules. Let's take each of them: 1....

Final classes

i camed across a nice C++ question which shows the final class principle (as I read here: http://www.codeguru.com/Cpp/Cpp/cpp_mfc/stl/article.php/c4143/ it seems that the final class specifier exist in Java) 1. A class that is not derived from a class nor is intended to have any class derived from it is an example of what type of class? A. A concrete class B. An abstract class C. A base class D. A virtual class E. A final class A final class is a class from which you dont derive (if you try to, the objects of the derived classes cant be constructed since the compiler will complain about this). So how can you design such class ? In C++ there is no keyword (final) to declare a class as non-inheritable as in Java. But then C++ has its own features which you may exploit to get the same behaviour. Basically it uses concepts of private constructor and friend class. For example, lets try to create a class called CFinal. class CFinal { // member data ... } We want to be able to use this class...

subtle difference when using const_cast

ive just read this article: http://www.devx.com/tips/Tip/5508 which shows the subtle difference (when is good \ bad) when using the const_cast on objects. thinking from the point of view of what a variable may contain (its value) and where this value is stored in computer memory, you can think of 2 kinds of const'ness: a 'true const': const int cn = 5; // true const variable; it might be stored in computer ROM and a 'contractual const': int num = 0; const int * pci = # // *pci is a contractual const int if you try to remove the constness of a variable in order to modify its value, its good to know wheater that variable is a 'true' or 'contractual' const. modifing a 'true' const variable is undefined (and not desirable to do). the idea is that a pointer to a const variable is still (just) a pointer containig the address of a variable. that variable, if you know that its not a true const (like const int num = 0) you can modify it safel...

name hidding again

the name hidding seems to be pretty compiler specific unfortunately. for example: struct A { int x; }; struct B: A { int x; }; struct C: A, B { void f() { x = 0; } }; int main() { C i; i.f(); } here http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=/com.ibm.xlcpp8a.doc/language/ref/cplr138.htm it says that "The assignment x = 0 in function C::f() is not ambiguous because the declaration B::x has hidden A::x." when i see this I was confused, what the hell; indeed, B::x hiddens A::x but since i is of C type, both B::x and A::x are available to C. i just put this code in Visual C++ 2003 and it gives (of course) the compile error: e:\Projects\test2\test2\test2.cpp(15): error C2385: ambiguous access of 'x' in 'C' could be the 'x' in base 'A::x' or the 'x' in base 'B::x' now, i bet that there are many things like this, compiler specific (the C++ ref from the link is for the IBM compiler); and this makes life har...

the best C++ reference

i dont think there is a better reference on C++ then these: Effective & More Effective C++ C++ Programming Language C++ Faqs Effective STL and... MSDN C++ reference MSDN yes, its really good; it has many C++ little language stuff you forget over time; although its short in description, if you have the time and patience, its good to read from time to time to refresh the concepts and things, but read it from start to end; it has many gritty things I (you) at time pass by, forget; also, it has many things you find in C++ books (but explained more better in books). btw, many of the stuff from my blog can be found in the MSDN C++ reference :D so why am I still writing here ? because its a good practice to actually explain in writing for myself different stuff

dominance

there is a thing called name dominance in C++. consider this: class A { public: int f() { printf("\nA::f()"); return 1; } }; class B : virtual public A { public: void f() { printf("\nB::f()"); } // hides the int A::f() }; class C : virtual public A { }; class D : public B, public C { }; the hierarchy is this: A B C D and D has only one copy of A in memory (beacuse B and C inherits virtual from A) now: D d; d.f(); f() is not ambigous because void B::f() hides int A::f(). d.f() will get B:f() called because D derives from B which hides the A::f(). Note that this is not ambigous beacause the A is virtual inherited in B and C and this makes that the d object to contain only one instance of A within it. if, for example, B or C will not have virtual inherited from A (either one of them or both) this will mean that d will have 2 A objects within it. now, consider this case: C *d = new D; d->f(); d->f() will get A:f() called. Why is that stays in the mechanism of call...

public inheritance broken

consider this: class A { public: void f(); void f(int x); } class B : public A { public: void f(); // hides all A::f() overloads } you have an object B b; and you want to call the f(int x) b.f(1); normally you would think that since B inherits A, it inherits all the A functions, which is true, but not when for overloading. the name f() declared in B class will override any base names. this includes the following case: class A1 { public: void f(); } class B1 : public A1 { public: int f; // hides all A1 'f'names } if you try to write the call: b1.f(); you will get a compile error as within a class, the names in a inheritance tree shoule be unique; if you want to preserve the is-a relationship(a derived class should access all public inherited base class functionality) then you need to declare in the derived class the base functions by using 'using' declarator: class B : public A {public: void f(); // hides all A 'f'names using A::f; //OK, now we have the A::f(int ...

Data alignment

Data alignment is (very?) important; or at least is very important to be aware of it when you write your code. Consider this: struct Broadcast { char timezone; // 1 byte data int frequency; // 4 byte data short timeofday; // 2 byte data }; applying the sizeof operator on the Broadcast (sizeof can be applied to a class) the result is 12 on a 32 bit operating system. this is because compilers usually round up a data structure's size to make it divisible by 2, 4, or 8—depending on the hardware's memory alignment requirements. Most CPUs require that objects and variables reside at particular offsets in the system's memory. For example, 32-bit processors require a 4-byte integer to reside at a memory address that is evenly divisible by 4. This requirement is called "memory alignment". Thus, a 4-byte int can be located at memory address 0x2000 or 0x2004, but not at 0x2001. On most Unix systems, an attempt to use misaligned data results in a bus error, which terminates ...