Part I 创建模式

下面是C++中创建对象的途径的一个综述:

  • 栈分配Stack allocation 对象在栈中创建, 对象会在退出作用范围时被自动清理. 此时对象的析构函数会被自动调用 (这个行为有时会破坏Mementom模式), 我们会在后面讨论.

  • 堆分配Heap allocation 使用原始指针(raw pointer) 指向在堆中分配的对象: Foo *foo = new Foo; 会创建一个新的Foo的实例, 并且将谁来负责释放它留给用户. GSL, https://github.com/Microsoft/GSLowner<T>尝试着将ownership的概念引入到raw pointer中而不额外引入任何的cleanup code–你仍然必须自己来写清理代码.

  • unique指针 (unique_ptr) 会使用堆分配的指针并管理它, 使得当它不再被使用时会自动清理. unique_ptr具有唯一性: 你不能拷贝它, 也不能将它传递给其他的函数的同时不放弃对它的控制.

  • shared指针 (shared_pointer) 使用并管理堆分配的指针, 并允许共享指针. 只有当没有其他的组件再持有这个指针时才会清理

  • weak指针 (weak_ptr) 没有所有权概念的指针, 持有一个由 shared_ptr 所管理的对象的弱引用. 要真正访问指针指向的内容, 需要先将其转换未 shared_ptr. 它主要的用途时打断 shared_ptr 的循环引用.

从函数中返回对象

当需要在函数中返回大于word的数据时, 有几种方法.

首先, 最常见的直接返回:

1
2
3
4
Foo make_foo(int n)
{
return Foo{n};
}

它创建了Foo的一份拷贝, 看上去似乎会浪费内存资源, 但实际上并不一定. 看下面的代码:

1
2
3
4
5
struct Foo
{
Foo(int n) {}
Foo(const Foo&) { cout << "COPY CONSTRUCTOR!!!\n"; }
}

你会看到Foo的拷贝构造函数执行的次数在0-2之间: 实际执行的次数取决于你使用的编译器.

返回值优化(Return Value Optimization, RVO) 是编译器特性, 它会阻止额外的拷贝.

在复杂的场景中, 你不应依赖于编译器的RVO特性, 但是在考虑是否要优化返回值时, 我更建议你遵守Knuth原则:

Donald Knuth, 在其著名的The Art of Computer Programming系列中曾经提到: “过早进行的优化时万恶之源 (premature optimization is the root of evil)”. C++所具有的过早优化能力格外诱人, 但是你应坚持这一原则, 直到: A) 你确切的知道自己在做什么. B) 你的确遇到了性能问题而需要优化性能.

另一种方法时返回指向对象的智能指针, 例如unique_ptr

1
2
3
4
unique_ptr<Foo> make_foo(int n)
{
return make_unique<Foo>(n);
}

这种做法很安全, 但是它提出一个问题: 为什么要使用unique_ptr? 如果人们更想用shared_ptr该怎么办?

最后一种做法是使用原始指针 (raw pointer), 可能的一种做法是是哟个GSL的owner<T>. 这种方式, 你并没有强制要求对分配对象的清理工作, 但是你清晰的表达了这样一个意思: 释放对象的资源是调用者的责任

1
2
3
4
owner<Foo*> make_foo(int n)
{
return new Foo(n);
}

Chapter 2 Builder

@import “Chapter_02_Builder.md”

Chapter 3 Factory

@import “Chapter_03_Factories.md”

Chapter 4 Prototype

@import “Chapter_04_Prototype.md”

Chapter 5 Singleton

@import “chapter_05_Singleton.md”

Part II Structural Patterns

@import “Part_2_Structural Patterns.md”

Chapter 6 Adapter

@import “chapter_06_Adapter.md”

Chapter 7 Bridge

@import “chapter_07_Bridge.md”

Chapter 8 Composite

@import “chapter_08_Composite.md”

Chapter 9 Decorator

@import “chapter_09_Decorator.md”

Chapter 10 Facade

@import “chapter_10_Facade.md”

Chapter 11 Flyweight

@import “chapter_11_Flyweight.md”

Chapter 12 Proxy

@import “chapter_12_Proxy.md”

Part III Behavioral Patterns

@import “part_3_Behavioral_Patterns.md”

Chapter 13 Chain of Responsibility

@import “chapter_13_Chain_of_Responsibility.md”

Chapter 14 Command

@import “chapter_14_Command.md”

Chapter 15 Interpreter

@import “chapter_15_Interpreter.md”

Chapter 16 Iterator

@import “chapter_16_Iterator.md”

Chapter 17 Mediator

@import “chapter_17_Mediator.md”

Chapter 18 Memento

@import “chapter_18_Memento.md”

Chapter 19 Null Object

@import “chapter_19_Null_Object.md”

Chapter 20 Observer

@import “chapter_20_Observer.md”

Chapter 21 State

@import “chapter_21_State.md”

Chapter 22 Strategy

@import “chapter_22_Strategy.md”

Chapter 23 Template Method

@import “chapter_23_Template_Method.md”

Chapter 24 Visitor

@import “chapter_24_Visitor.md”

Appendix A Functional Design Patterns

@import “Appendix_A_Functional_Design_Pattern.md”

Chapter 25 Maybe Monad

@import “chapter_25_Maybe_Monad.md”