Spockwang's Blog

C++ Gotchas

| 评论

Variables, Operators and Conversions

Implicit conversions are not applied to non-const reference arguments. See p.146 of [C++].

The distinction between const-reference and non-const reference parameters is that the former matches constants and const variables while the latter matches others in overloading resolution. Const-reference can bind temporary objects but non-const reference can not.

Not like C, consts have internal linkage by default. However, you can use extern to give it external linkage. See bottom of p.199 of [C++].

There are four kinds of cast in C++: static_cast, dynamic_cast, const_cast, and reinterpret_cast.

Initialization

The global objects and class static member objects are constructed according to their order of definition (section 9.4.1 of [C++]). The local static objects are constructed when accessed the first time (See section 7.1.2 of [C++]). They are destructed in the reverse order. An array of class objects are initialized by calling corresponding constructors for each of its elements, following the subscript order (clause 3 of 12.6 of [ISO C++ 1998]).

The objects with static storage duration is first zero-initialized (Section 8.5 of [ISO C++ 1998]) and then initialized by calling appropriate constructors. Local non-static objects which are class type are initialized by calling appropriate constructors (call default constructors if no initializers). Local non-static objects which are built-in types have indeterminate initial values. On initialization of non local objects see 3.6.2 of [ISO C++ 1998]. On initialization of static objects see clause 4 of section 6.7 of [ISO C++ 1998].

Program Termination

  • By exit(): destructors for local objects are not called; destructors for constructed static objects are called.
  • By abort(): all destructors are not called.
  • By throwing an uncaught exception: all destructors are not called.
  • By returning from main(): all destructors are called.
  • See p.218 of [C++].

Operator Overloading

Overloaded operator functions must either be a member or take at least one argument of a user-defined type. See 11.2.3 of [C++].

std::endl vs. “\n”

std::endl causes the stdout stream to be flushed while \n does not.

Pass overloaded function as an template parameter

Be wary when passing overloaded functions as template parameter. Because the passed function is not given any argument the compiler does not know which version of the overloaded function to call. So you must explicitly supply template parameters with the function.

Class

A friend function should either be explicitly declared in an enclosing scope or take an argument of its class. If not, the friend cannot be called. See p.280 of [C++].

A function member of a derived class is not in the same scope as a function member of the same name in a base class. See section 13.2 of [ISO C++ 1998]. So the function of a derived class can not overload the function of the same name in the base class, because overloading can only happen among the same names in the same scope.

The scope of typedef types in class declaration begins from where it is defined to the end of class declaration, while the scope of class member variables and functions extend to the whole range of the class declaration.

If a function does not catch an exception destructors of local objects of that function will not be called. (See section 9.4.1.1 of [C++].)

A function in derived class with more restricted access right can override the same function in the base class. For example, a private function in a derived class can override the same public function in the base class. Then I can access the private function in the derived class through virtual mechanism. I think it is a loophole in the C++ grammar. It is not allowed in Java.

Constructors can not be virtual but destructors can be virtual, and sometimes it must be. Calling virtual functions in constructors and destructors have the same effect as calling non-virtual functions. The usual virtual mechanism does not make effects, because the virtual pointer is pointing to the virtual function table of this class, not the class of the actual object.

Unlike Java, you cannot define static class within another class.

The class defined in another class is not special in C++. The member functions of embedded classes can access all fields (regardless of access rights) of the enclosing class. The enclosing class has not any special access rights to the inner class. It is not allowed to access the private or protected members of the inner class.

In the absence of an access-specifier for a base class, public is assumed when the derived class is declared struct and private is assumed when the class is declared class.

class B { ... };
class D1 : B { ... }; 	// B private by default
struct D2 : B { ... };	// B public by default

Static variables declared in a function member of a class, like static variable member, is shared by all objects of this class.

Assignment operator

  • Obliterate existing object;
  • Check for self-assignment;

Assign to all data members, including those from base classes (by calling assignment operators of base classes)

Constructor

The constructor of a class must specify a mem-initializer for all its virtual base classes (direct or indirect) and direct base classes if they do not have an accessible default constructor (clause 6 of 12.6.2 of [ISO C++ 1998]).

References

  • [C++] The C++ Programming Language, Third Edition.
  • [ISO C++ 1998] The C++ Standard, 1998.

Comments