Introduction
View C++ as a federation of Languages
In Scott Meyer’s opinions, Modern C++ supports different paradigms of programming, including
C
,Object-Oriented C++
,Template C++
(with its byproduct ofC++ Template Meta Programming
, short forCTMP
) andSTL
.
The Enum Hack
e.g.
1
2
3
4
5
6
7
8 class GamePlayer {
private:
enum { NumTurns = 5 }; // To make "NumTurns"
// a mark name of 5.
int scores[NumTurns]; // That would be alright.
...
};Enum Hack可以替代宏定义常量,实现几乎相近的行为。没有名字的enum在编译时直接被编译器替换,不占用额外的内存。可以说是非常经济实惠的做法。(Enum Hack在C中也可以运用)
Overload the function with different constness
We always neglect the fact that two member functions with different constness can be overloaded.
e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 // a template class of Array:
template<class _Ty, size_t _Size>
class
Array
{
...
typedef _Ty& reference;
typedef const _Ty& const_reference;
public:
...
const_reference operator[](const size_t&) const noexcept;
reference operator[](const size_t&) noexcept;
private:
...
};
// const version of operator[]:
template<class _Ty, size_t _Size>
inline
typename Array<_Ty, _Size>::const_reference
Array<_Ty, _Size>::operator[](const size_t &__index) const noexcept
{ return *(begin() + __index); }
// non-const version of operator[]:
template<class _Ty, size_t _Size>
inline
typename Array<_Ty, _Size>::reference
Array<_Ty, _Size>::operator[](const size_t &__index) noexcept
{
return const_cast<_Ty&>( // cast away the constness;
static_cast<const Array&>(*this) // cast *this into a const
[__index] // reference to call the
); // const version of operator[];
}
Use
mutable
to change member variables at will.
Assign the similar initialization tasks to member functions declared
private
ordelegation constructors
to avoid the mechanical repetition of codes.
Realize simple
singleton
by:
1
2
3
4 Obj &SingletonFact() {
static Obj object {params};
return object; // return the handle of object
}
Constructor, Destructor, Assignment
Forbid the unwilled operations
Add an
= delete
at the end of the function to forbid the call of them.(AfterC++11
)
EBO(To Be Continued)
Don’t declare function as virtual if unnecessary
Object must contain some information to judge which version of function to be called,
This information is usually pointed out by a pointer called
vptr(virtural table pointer)
which points an array made up of function pointers, calledvtbl(virtual table)
, which causes the expansion of the size of objects.
Pure Virtual Function makes the class abstract
1
2
3
4
5
6 class Sample {
...
virtual ~Sample() = 0; // Sample cannot be instantiated now.
}
Sample::~Sample() { };
Never call a virtual function when the object has not been initialized
We can memorize it by a recipe: “Virtual function is not a virtual function, when the object is under construction.” Basically, the call of virtual function in this section violates the principles of
runtime polymorphism
.
Use
Identity Test
to avoid the self-assignment
1
2
3
4
5
6
7 Widget &Widget::operator=(const Widget &rhs) {
if(this == &rhs) return *this; // Identity Test.
delete pb; // pb is a member of Widget which points a Bitmap;
pb = new Bitmap(*rhs.pb);
return *this;
}
copy-and-swap
strategy may function well
1
2
3
4
5 Widget &Widget::operator=(const Widget &rhs) {
Widget temp(rhs);
swap(temp);
return *this;
}
Resource Management
Smart Pointer
下面是一个工厂函数:
1 Investment *createInvestment();我们希望构造的
Investment
在超出生命周期后立马被析构。那么我们可以用只能指针来封装Investment *
。Smart pointer uses reference count as its gist to judge if the pointer packaged shall expire.
std::unique_ptr
can be referred to only once.
std::shared_ptr
can be referred to several times.
Circular Reference
std::shared_ptr
should be combined withstd::weak_ptr
to avoidcircular reference
.A Sample of
Circular Reference
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 class A
{
public:
~A() {cout<<"A Expired"<<endl;}
shared_ptr<B> b;
};
class B
{
public:
~B() {cout<<"B Expired"<<endl;};
shared_ptr<A> a;
};
void Test()
{
shared_ptr<A> pa(new A);
shared_ptr<B> pb(new B);
pa->b = pb;
pb->a = pa;
}调用
Test()
后发现A, B的析构函数均未被正常调用。这个过程如下:
pa想要被析构,但pa的引用仍然被pb所指对象所把持,导致pa无法被析构。而pb也是如此,无法被正常析构。
我们只要把其中一个
shared_ptr
替换成weak_ptr
即可。weak_ptr
不具备资源管理的能力,其只提供了一个expired()
接口检测资源是否被释放。
A Class Intended for Resource Management
Two Critical Criterion:
- RAII, 获得资源后立刻放入资源管理对象。
- 管理对象运用析构函数确保资源被释放。