Name and Type
1.
The scope of a derived class is treated as
nested in its base class when it comes to name lookup. (help understand hiding)
2.
Decltype yields the corresponding type for a
VARIABLE and a reference for assignable EXPRESSION, and a value for
non-assignable EXPRESSION. e.g.
decltype(ref_int + 0) //int
decltype(val_int) // int
decltype ((val_int)) // int &
decltype(ref_int + 0) //int
decltype(val_int) // int
decltype ((val_int)) // int &
3.
In implicit type conversion, char is promoted to
int, not short.
Pointer and Reference
4.
A past-the-end pointer is not an invalid
pointer. Though it also should not be dereferenced, it can be used to compare
with the other pointers pointing to the same array. In contrast, comparing two
pointers pointing to two unrelated object is UB.
5.
A reference is always treated as the object it
refers, such as, sizeof(ref), typeid(ref), etc, all info is about the
underlying object, with only one exception: decltype(ref) gives the reference
type.
6.
A pointer got from new Type[0] is not a nullptr
but a pass-the-end pointer, it serves just like vec.end() when the vector is
empty.
7.
Use std::less<T> ()(a, b) instead of
‘<’ when writing a template. Because if T are pointers and they are not
pointing to the same array, using ‘<’ on them is UB.
Ctor/Dtor
8.
A ctor can serve in static_cast.
9.
Inherited ctors inherits explicit/constexpr
properties. It does not inherit default arguments. Instead it gets multiple
ctors in which each parameter with a default argument is successively omitted.
10.
If a class defines a dtor, even if it uses
=default, the compiler will not synthesize a move operation for that class.
11.
The reason why the member initialization order
depends on the definition order rather than the order in which they appear in
the initialize list is, dtor must reverse the order and there is no way for a
dtor to know the order in which you initialized the members.
12.
When you use ‘=default’ to force a compiler to
generate a default move ctor for your class, but the compiler cannot (e.g. not
all members are movable), the compiler will turn it into ‘=deleted’.
Move
13.
Compiler uses the copy ctor for move if you do
not provide one. But, if you refuse to provide any copy-control members
(assignment operator, copy ctor, etc) and all non-static data members are
movable, you will get a real synthesized move ctor from compiler.
14.
IO stream object can be moved.
15.
After move operation, do not assume any state of
the moved obj. e.g. People may assume a
moved vector has size() as 0 and the call of empty() on it return true. But it
is not necessarily the case: perhaps the underlying whole pimpl object was
moved away, the call of empty() or size() are forwarded to a null pointer.
16.
The std::containers only move its elements when
the elements have a nonexcept move ctor. Otherwise it cannot guarantee
exception safety when moving the container. (Is this part of the reason that
VC11 does not support nonexcept keyword yet?)
17.
Classes that define a move ctor/assignment
operator must also define their own copy operations; otherwise, those copy
operations are defined as $deleted$ by default.
18.
You can use a move_iterator when you want to
move all elements from a container to another.
Functions
19.
Using directives create an overlord set of
functions from different namespaces:
using namespace sp1; //has print(int)
using namespace sp2;//has print(double)
…
print(1); //sp1::print
print(1.2);//sp2::print
…
using namespace sp1; //has print(int)
using namespace sp2;//has print(double)
…
print(1); //sp1::print
print(1.2);//sp2::print
…
20.
When looking for a best match for overloaded
functions, the non-member (normal) functions and member functions race
together.
21.
Each function default parameter can have its
default specified only once. Any subsequent declaration can add a default only
for a parameter that has not previously had a default specified.
int f(int , int = 2); int f (int =1, int);// OK, incremental specification
int f(int , int = 2); int f (int =1, int);// OK, incremental specification
22.
Static member can be used as a default argument
before definition and even declaration (but, ofc, the declaration should
exist).
Member functions
23.
When using = default, (as with other member
fuctions), if it appears in class, the default ctor will be inlined; if it
appears outside the class, it is not by default.
24.
Besides const, you can place a reference
qualifier on a member function to indicate this pointer is pointing to a rvalue
or lvalue. E.g.
void mem_func(int ) const &&
means, mem_func(const && this_obj, int); The && here has nothing to do with move semantic. It avoids some silly statement like : str0 + str1 = “abc”. Operator=() should certainly behave differently when *this is a rvalue or a lvalue.
Btw, it is nice but not supported by many compilers yet.
void mem_func(int ) const &&
means, mem_func(const && this_obj, int); The && here has nothing to do with move semantic. It avoids some silly statement like : str0 + str1 = “abc”. Operator=() should certainly behave differently when *this is a rvalue or a lvalue.
Btw, it is nice but not supported by many compilers yet.
25.
=default is used when defining a function while
=deleted is used when declaring a function.
26.
We can provide a definition for pure virtual
function, but we can only write it outside the class.
27.
Virtual function can have default argument, but
the one used is determined by its static type. No RTTI for this kind of work.
28.
Member functions can also be defined as
volatile, only volatile member functions can be called on volatile objects.
Lambda
29.
Lambdas are function objects with deleted
default ctor, deleted assignment operators and default dtor and it has a member
‘operator()’ which is a const member by default. Whether it has a defaulted or
deleted copy/move ct depends on the captured data members.
30.
The value (as opposed to reference) captured by
a lambda is const. You can override its constness by adding a mutable keyword
following lambda.
31.
In a lambda function, when the return type is
not specified, the function body is just a return statement, the return type is
inferred from it, or it is void.
32.
We can omit parameter list and return type of
lambda. So a simplest form and fully spelled formed should be:
auto f = []{};
auto f = [captures](parameters) mutable -> returntype {}
auto f = []{};
auto f = [captures](parameters) mutable -> returntype {}
Template
33.
Template member function cannot be virtual.
34.
We can make a template type parameter a friend.
template <typename Type> class Bar{friend Type;}
It is OK when it is instantiated with a built-in type.
template <typename Type> class Bar{friend Type;}
It is OK when it is instantiated with a built-in type.
35.
Instantiation also happens (if not yet) when
assigning the template function to a function pointer / reference.
Access control
36.
Other than narrowing down the access control
during inheritance (by public, protected, private derivation), we have a way to
enlarge it:
class Derived: private Base{
public:
using Base::protected_member;
}
Now, protected_member is public.
37.
The protected/public member can be accessed from
derived class, even if it uses private derivation. The access control of
private derivation has effect on how to use the derived class, not the base
class.
38.
Normal access controls apply to pointers to
members.
STL:
39.
The STL containers now have a cbegin() and cend,
which are specifically designed for auto:
auto citer = vec.cbegin()//always const_iter regardless the container type.
auto citer = vec.cbegin()//always const_iter regardless the container type.
40.
Std::swap() only invalidates the iterators on
std::string. It does not invalidate iterators on other types of containers.
They are pointing to the same elements in the swapped container.
41.
Forward_list does not have size(). (I do not
know why exactly)
42.
Forward_list is different, it inserts_after,
etc, and uses an off-the-beginning iterator.
43.
String library now have string-to-numeric
converting functions.
44.
Reverse_iterator.base() does not yield the
adjacent position rather than the same one.
45.
Use make_pair, make_tuple to let compiler deduce
types for you.
46.
Iterators for std::set, either cons_iterator or
(non-const) iterator are both onst_iterators.
47.
Bitset subscription operator [] counts from
right to left.
48.
We can use std::function to store a function
directly but cannot when it has overloaded versions:
int func(int, int);
int func(double, double);
std::function<int(int, int)> f = func; //which?
int func(double, double);
std::function<int(int, int)> f = func; //which?
Use a pointer or reference to deambiguate:
int (&funcii )(int , int) = func;
std::function<int(int, int)> f =
funcii;
49.
The seekg, seekp, tellg, tellp uses the same
marker on fstream and stringstream.
Other
50.
Sizeof (*a_null_pointer) is valid. Sizeof (char)
is guaranteed to be 1, always.
51.
An enumerator value need not to be unique: enum
{A = 1, B = 1, C = 1}; //it’s OK
52.
A definition of a nested class can be outside
the enclosing class.
53.
A local class is legal but must be completely
defined in the class body.
54.
A constexpr is not required to return a const
expression always
55.
A constexpr is not required to be defined when
the literal value is used. But it still needs a definition when the run time
properties (like address operator &) are required.
56.
Friendship is not inherited. But, a friend of
Base class can access the members of Base part of a Derived object.
57.
Virtual base classes are always constructed
prior to non-virtual base classes regardless of where they appear in the
inheritance hierarchy.
58.
noexcept specifier
should not appear in a typedef or type alias.
59.
The compiler will generate (when needed) the
nonexcept ctor / copy-control members / dtor if the corresponding operations
for all of its members promise not to throw.
60.
A
function pointer that not specifying noexcept can point to noexcept functions,
but NOT otherwise.