CS106L笔记
CS106L
前言:
适用人群:我个人觉得非常适用于已经对c++有所了解,或者修读过类似于高级语言程序设计这样的课程,想对c++有进一步的研究的同学。
课程难度对我来说挺大,一方面是全英文,另一方面,c++讲到的东西,确实比c多了很多,以前学的c++,反而有些像套了一点壳的c,面向对象,泛式编程的思想都没悟透。
课程链接:https://www.youtube.com/watch?v=_WvkljZzGug&list=PLCgD3ws8aVdolCexlz8f3U-RROA0s5jWA&index=3
(我看的是2019年版本的,因为看起来比较全)slides and assignments: https://web.stanford.edu/class/archive/cs/cs106l/cs106l.1184/lectures.html
http://web.stanford.edu/class/cs106l/提供的代码需要在Qt下运行,并且版本要大于6.0(害得我重装了5.9.9的Qt()。斯坦福官方给出的教程链接:https://web.stanford.edu/dept/cs_edu/resources/qt/install-windows
Lec 0 Intro
the course’s goal:
- Learn the feature of cpp
- Become comfortable with cpp documentation
- Familiar with the design philosophy of modern cpp
History:
Assembly->C->C++
C’s weakness
No
objects
orclasses
Difficult to write code that worked generically
Tedious when writing large programs
Design Philosophy of C++:
- Allow the programmer full control, responsibility, and choice if they want it.
- Express ideas and intent directly in code.
- Enforce safety at compile time whenever possible
- Do not waste time or space
- Compartmentalize messy constructs
cpp is a multi-paradigm programming language
- generic programming
- object-oriented programming
- ..
Lec 1&2 Stream
stringstream
two key steps:
state bits:
four standard output ways:
variables declared in the loop can only be used within the loop. They can’t be used outside the loop.
还是直接上代码的好..
1 |
|
When should use stringstream?
- Processing strings
- Formatting input/output
- Parsing different types
When u want to just concatenate some strings, it’s faster to use str.append()!!
Type
1 |
|
uniform initialization
c++ has many many initializations.
Therefore, a automatically deduced declaration is highly praised. This is called Uniform initialization in C++ 11.
1 |
|
reference
1 |
|
Lecture 3 Sequence Containers
example
With the power of STL, some operations can be done in a few steps. This gives you the extra time to understand the problem in more depth
.
1 |
|
sequence containers
1 |
|
Lec 4 Associative Containers
Container Adaptors
using deque
Associative Adaptors
map/set: iterate
unorderd_map/unordered_set : access individual
1 |
|
iterator
non-linear to linear
(inner method: in-order traversal)
*iter to dereference
.end()
advantage: tackle problems in a standardised way
five kinds of iterators:
- Input Iterators.(can only access elements)
- Output Iterators.(can only assign elements)
- Forward Iterator.(input & output, but can only move in the forward direction)
- Bidirectional Iterators.(Forward, and can also move backwards)
- Random-Access Iterators.(move randomly like pointers)
Lec 5 Advanced Containers
Multimaps
the same key has multiple values
examples
1 |
|
Lec 6 Templates
1 |
|
Lec 7 Templates and Functions
Implicit Interface
1 |
|
In c++ 20, it added named requirements on the template arguments.
lambda
my problem: need a generic function like
1 |
|
how to tackle?
- using function pointer
- lambda
(上学期写数据结构的时候正好考虑到了这个需求,并且想得一模一样!听到这里真的很激动
1 |
|
Lec 8 Functions and Algorithms
Remain
using reference capture in lambda: auto someFunc = [&vec](){ //.. };
Algorithms
1 |
|
erase-remove idiom
1 |
|
ostream_iterator
1 |
|
bind and placeholders
https://www.geeksforgeeks.org/bind-function-placeholders-c/
1 |
|
Lec 9 STL Summar
Iterator Adapter:
1 |
|
more applications like boost library, multi-thread programming..
Key Concept: Abstraction
这堂课带着写代码,还是挺有收获的。
1 |
|
Lec 10 Classes and Const Correctness
c/c++ extensions
from this link:
There are at least four different extensions usable for C++ files:
- .C
Not very popular since it requires a case-sensitive file system (otherwise, it would clash with old .c file names), and even a few modern OS are not case-sensitive.- .c++
Some OS or file systems don’t support the + character in file names.- .cpp
That’s very portable across file systems.
But, it might be less consistent than .cxx- .cxx
Very portable across file systems (not more than .cpp)
Using the name CXX for C++ is quite popular because CPP usually designates the C (and C++) pre-processor.For headers, there are at least five extensions:
- .h
Traditional C header files.
Since the compiler doesn’t do anything based on this extension, it can be used for C++ header files too.
Furthermore, there are a lot of header files that are designed to be included by both C and C++ translation units.
In that case, it’s natural to give them this extension.- .H, .hpp or .hxx
That’s very natural to give one of these extensions for C++ header files (being consistent with the name of C++ translation units).
That’s not a bad idea to use one of these name for pure C++ header files only (containing class definitions, or templates, or any other feature not supported by C).- No extension
That’s internally used by a number of C++ compilers for iostream, vector, algorithm and all others new-style C++ headers.
why don’t use global variables
“Global variables can be read or modified by any part of the
program, making it difficult to remember or reason about
every possible use”“A global variable can be get or set by any part of the
program, and any rules regarding its use can be easily broken
or forgotten”“Non-const variables can be read or modified by any part of
the function, making it difficult to remember or reason about
every possible use”“A non-const variable can be get or set by any part of the
function, and any rules regarding its use can be easily broken
or forgotten”
const
const value
1 |
|
const member function
1 |
|
const class non-const class
1 |
|
const pointer
1 |
|
const iterators
1 |
|
Lec 11 Operators
operator overloading
1 |
|
operator overloading is or is not a member function?
- Assignment (=), subscript ([]), function call (“()”), and member selection (->) operators must be defined as member functions
- some(like
<<
) must be be defined as non-member(we write for rhs, but not lhs) - symmetric operation should be non-member functions, so we can prevent situations like,
a + 1
is legal,1 + a
is illegal - unary operation should be used as member function, so we can easily change the private value
- some binary operation(e.g.
+=
) should be member function, too. Or it’s hard to change the inner value.
POLA
principle of least astonishment
if a necessary feature has a high astonishment factor, it may be necessary to redesign the feature.
copy
shallow copy/deep copy
比如说,对于一个对象,如果里面有new出来的数组,如果只是对其浅拷贝,那么它默认只会获取new的那个指针,而不是整个数组,因而拷贝和被拷贝的对象的数组,指向的是同一段内容。而深拷贝则需要手动制定,以将两者区别开来。
Lec 12 Special Member Functions
recap
1 |
|
copy construction vs copy assignment
these special functions will be created by compiler, but they won’t always work, especially with something irrelated to the class itself(like heap, stream, etc)
default construction
copy construction
copy assignment
destruction
what’s the difference between construction and assignment?
https://www.geeksforgeeks.org/copy-constructor-vs-assignment-operator-in-c/
https://www.geeksforgeeks.org/copy-constructor-in-cpp/
(geeksforgeeks is really recommended!)
e.g.
1 |
|
Therefore, the codes below can’t run correctly, cause the copy is just a shallow copy.
这部分还是挺重要的,还是切换成中文说吧。下面这样copy = vec
,在没有自己定义复制构造函数的情况下,只会执行系统默认编写的复制构造函数。系统自己写的特点是什么呢?只能浅拷贝(shallow copy),如果成员有复制构造函数可以拷贝,就直接拷贝,而不能直接调用class之外(例如,new出来的内存)之类的东西。
再看下面这个函数。他的第二句话vector<int> copy = vec;
,实际上就是直接执行了系统编写的浅拷贝。原来vector里的size等变量,可以直接浅拷贝过来。但如果vector里面,还有一个*elem数组,并且new出了一段内存来存储数据的话,那么这个复制构造函数,并不会将所有数据全部拷贝到一个新数组里,而只是构造出一个指针,指向的内容还是原来的数组。但是在退出函数时,copy就被销毁了,不仅没有拷贝回来,还带回来一个野指针。
1 |
|
这个时候,就需要我们自己写一个copy constructor:
1 |
|
rule of three/zero
When do you need to write your own special member functions?
when the default one generated by the compiler does not work.(e.g. pointers, streams, those are pointed to outside resources.
Rule of Three: If you explicitly define (or delete) a copy constructor, copy assignment, or destructor, you should define(or delete) all three.
1 |
|
RVO
**Return Value Optimization
**,即,编译器会对函数的返回值进行编译优化,减少不必要的copy。
例如,某函数要return的是函数体内的一个x变量,然后我们将其赋给main里的变量a(即,a = func();
),照道理x需要再被拷贝一下(尽管这不是必要的),然后返回这个copy,然后x被摧毁。但是此时编译器会捕捉到这个细节,直接在a上进行赋值,减少拷贝。
去掉这种优化的办法:
1 |
|
Lec 13 Move Semantics
c++的vector
里有emplace_back
和push_back
两种函数,前者接收右值,后者接收左值。示例如下:
1 |
|
wasted copy->move directly
lvalues vs rvalues
lvalue:
- can find name(identity) -> &var is valid
rvalue:
- opposite: can’t find &var
move constructor and assignment
move(steal) from rvalue
rvalue can be copyed or moved, as it’s disposable.
这是一种可行但是并没有真正用到rvalue和move精髓的代码:
为什么呢?因为尽管它传入的是右值的引用,但事实上,在这个函数里,它是一个左值,这个时候,就需要用到move
表示其为右值:
原课程的PPT:
因此,原先的rule of three变为了rule of five,即需要额外指定move constructor
and move assignment
:
swap
在原先的swap基础上,加上move
使其转为右值,以减少原先作为左值的额外拷贝。
1 |
|
perfect forwarding
读了很多,很有意思,不过也很难..其实主要解决的问题还是,在函数参数中的右值引用,在函数本体里仍然有可能作为一个左值存在。
Perfect forwarding requires forwarding references in order to preserve the ref-qualifiers of the arguments. Such references appear only in a deduced context. That is:
1
2
3
4
5
template<class T>
void f(T&& x) // x is a forwarding reference, because T is deduced from a call to f()
{
g(std::forward<T>(x)); // g() will receive an lvalue or an rvalue, depending on x
}The following does not involve perfect forwarding, because
T
is not deduced from the constructor call:
1
2
3
4
5
template<class T>
struct a
{
a(T&& x); // x is a rvalue reference, not a forwarding reference
};
在template的帮助下,函数可以对x的类型作出推断,判断其为左值或右值,这样在接下来的函数里,就不会出现右值变成左值的可能。
Lec 14 Inheritance
1 |
|
namespace
1 |
|
inheritance
感觉上不如软荣上实践得来的经验多..得去CS108才能得到更好的锻炼。
不过有一句还是值得摘录的:No “virtual” members - instead, if a member has the same name as as inherited member,it hides it.