DataStructureAndAlgorithmInC++学习笔记 (一)
- 递归:1. base condition 2. make procress to base
int f (int x) {
if (x == 0) {
return 0;
} else {
return 2 * f(x - 1) + x * x;
}
}
void PrintDig(int x) {
if (x >= 10) {
PrintDig(x / 10);
}
cout << x % 10;
}
- base case & make process
- 声明类对象的构造函数调用不当时,编译器可能会当成函数声明:
IntCell i1(); // 可能会被当作范围IntCell类型的函数
IntCell i1;
IntCell i1{}; // 如果希望零参调用构造函数,要么不带括号,要么带花括号。
- range-for 遍历并且不需要下标时可以采用
int result = 0;
for (int idx : target) {
result++;
}
// 或者通过左值引用来修改被遍历的元素
for (auto& elem : target) {
elem++;
}
-
左值引用的用途
- 给复杂结构起别名,提高代码可读性
- range-for 循环中修改迭代元素
- 避免返回时大对象的复制
-
模板函数与构成类的基本元素
template <typename type>
const type& FindMax(const vector<type>& vec)
{
int maxIndex = 0;
for (int i = 0; i < vec.size(); i++>) {
if (vec[i] > vec[maxIndex]) {
maxIndex = i;
}
}
return vec[maxIndex];
}
#ifndef INTCELL_H
#define INTCELL_H
class IntCell()
{
public:
explicit IntCell(int val = 0) : storedValue(val);
int read();
void write(int val);
private:
int storedValue;
};
#endif
lvalue: 被命名的非临时变量
rvalue: 没有被命名的但又确实存储在某个地方的临时变量(赋值符右边的准备赋给左边的这个计算结果或者函数返回的临时变量就是rvalue)
右值的这个临时变量是在什么时候释放?
右值引用比左值引用多一个特征就是可以引用右值,其余一样。
std::move()可以把值变成右值来避免左值复制时的copy开销,主要使用场景是移动赋值与移动构造函数,需要注意的是左值在调用过std::move()后将无法继续使用,因为移动构造函数会将传入的右值置空。
带bigFive的intCell
class IntCell()
{
public:
explicit IntCell(int val = 0)
{
sotredVal = new int{val};
}
~IntCell()
{
delete storedVal;
}
IntCell(const IntCell& rhs)
{
storedVal = new int{*rhs.storedVal}; // 一定要清楚调用变量的类型
}
IntCell(IntCell&& rhs)
{
storedVal = rhs.storedVal;
rhs.storedVal = nullptr;
}
IntCell& operator=(const IntCell& rhs)
{
if (this != rhs) {
IntCell tmpCell = rhs;
std::swap(*this, tmpCell);
}
return *this;
}
IntCell& operator=(IntCell&& rhs)
{
std::swap(storedVal, rhs.storedVal); // swap member-by-member
return *this;
}
int Read() const // 写每个函数时,花十秒想一下返回类型,入参,可读性,内部逻辑
{
return *storedVal;
}
void Write(int val)
{
if (*storedVal !=val) {
*storedVal = val;
}
}
private:
int *storedVal;
};
- 模板函数 模板类 函数对象
template <typename obj, typename cmp>
const obj& FindMax(const vector<obj> vec, cmp isLessThan)
{
int maxIndex = 0;
for (int i = 1; i < vec.size(); i++) {
if (isLessThan(vec[maxIndex], vec[i])) {
maxIndex = i;
}
}
return vec[maxIndex];
}
class CaseIntensiveCompare
{
public:
bool operator()(const string& lhs, const string& rhs) {
return lhs.size() < rhs.size();
}
};
int main()
{
vector<string> vec = {"ma", "junsong"};
cout << FindMax(vec, CaseIntensiveCompare{});
}
- 第一章 总结
右值 右值引用 右值拷贝 右值赋值等C++11新增的特性是为了解决临时对象在传参、返回、拷贝、赋值时造成的复制开销。
swap : member-by-member 与 three move, 后者是通过move和copy assignment来实现的,所有copy assignment如果试图通过swap来实现的话 只能是member-by-member. 否则就会出现循环调用。
range for 的前提是容器支持迭代器。
move & assignment移动赋值的声明与使用
Object& operator= (Object&&);
Object newObject = std::move(oldObject);
把swap理解得太片面导致了误区,不只是threeCopy和threeMove三次swap std::move(); 也可以member-by-member swap
原文如下:
Finally, the move assignment operator at lines 23–27 is implemented as a member-by-
member swap. Note that sometimes it is implemented as a single swap of objects in the
same manner as the copy assignment operator, but that only works if swap itself is imple-
mented as a member-by-member swap. If swap is implemented as three moves, then we
would have mutual nonterminating recursion.
构造一个新的对象时 不管是=还是() 都是调用的构造函数。赋值函数只对已有对象的赋值起作用
- 点赞
- 收藏
- 关注作者
评论(0)