文章目录
- 1. 计算机内存
- 1. 储存层次
- 2. 内存单元与地址
- 3. 指针定义
- 2. 左值与右值
- 1. 数组与指针
- 1. 概念
- 3. C++中的原始指针
- 1. 数组指针与指针数组
- 2. const pointer 与 pointer to const
- 3. 指向指针的指针
- 4.关于野指针
- 4.1 指向指针的指针
- 4.2 NULL指针
- 4.3 野指针
- 5. 指针的基本运算
- 5.1 & 操作
- 5.2 *操作
- 5.3 ++和--操作
- 5.4 ++++与----运算符
- 6. 内存分配
- 6.1 总览
- 6.2 heap堆
- 6.3 分配和回收动态内存的原则
- 6.4 资源管理方案--RAII
- 6.5 c++中几种变量的对比
- 6.6 内存泄漏问题
- 4 更安全方式使用指针
- 1. 智能指针
- auto_ptr
- unique_ptr
- shared_ptr
- weak_ptr
- 2. 引用
- 为何使用引用
- 引用的使用
- 函数传递总结
慕课网C++课程
1. 计算机内存
1. 储存层次
2. 内存单元与地址
3. 指针定义
2. 左值与右值
1. 数组与指针
1. 概念
3. C++中的原始指针
1. 数组指针与指针数组
2. const pointer 与 pointer to const
- 测试
- 数组只是指向了一块字符空间,没有自己真实的地址
- pStr1指向了数组指向的字符的地址,编译器做了优化
- pStr2-指针变量本身的地址,为字符数组地址
- pStr3地址指向的字符串内容不能有任何改变
- pStr2指针的内容可以改变,但是与pStr1指针指向的内存一致,因此,虽然pStr1只读,但pStr2改变后,pStr1指向内容还是发生了改变
3. 指向指针的指针
4.关于野指针
4.1 指向指针的指针
4.2 NULL指针
4.3 野指针
5. 指针的基本运算
5.1 & 操作
- 取地址的值,只能做右值,取到地址后,作为一个空间变量,可以赋给一个指针,
- 但是取特定空间的地址操作不能做左值,即,不能通过取地址操作改变地址
5.2 *操作
- 右值,是取指针指向地址空间上的对象值
- 左值,是取指针指向的地址空间,可以对地址进行操作
5.3 ++和–操作
- 不能作为左值,只是一个中间的副本,没有明确的地址
5.4 ++++与----运算符
6. 内存分配
6.1 总览
6.2 heap堆
6.3 分配和回收动态内存的原则
6.4 资源管理方案–RAII
6.5 c++中几种变量的对比
6.6 内存泄漏问题
4 更安全方式使用指针
1. 智能指针
auto_ptr
- new的对象出了作用域,会自动删除
- 指针设置为空,用
nullptr
,NULL
是c语言语法,有二意,建议用nullptr
对指针设空
unique_ptr
#include "stdafx.h"
#include <memory> // 智能指针
#include <iostream>
using namespace std;
int main()
{
// 在这个范围之外,unique_ptr被释放
{
auto i = unique_ptr<int>(new int(10));
cout << *i << endl;
}
// unique_ptr
auto w = std::make_unique<int>(10);
cout << *(w.get()) << endl; // 10
//auto w2 = w; // 编译错误如果想要把 w 复制给 w2, 是不可以的。
// 因为复制从语义上来说,两个对象将共享同一块内存。
// unique_ptr 只支持移动语义, 即如下
auto w2 = std::move(w); // w2 获得内存所有权,w 此时等于 nullptr
cout << ((w.get() != nullptr) ? (*w.get()) : -1) << endl; // -1
cout << ((w2.get() != nullptr) ? (*w2.get()) : -1) << endl; // 10
return 0;
}
shared_ptr
- 需要一个引用计数的信号量控制
weak_ptr
- 解决循环引用的问题
- 用法示例
- shared_ptr 内部是利用引用计数来实现内存的自动管理,
- 每当复制一个 shared_ptr,引用计数会 + 1。当一个 shared_ptr 离开作用域时,引用计数会 - 1。
- 当引用计数为 0 的时候,则 delete 内存。
// shared_ptr
{
//shared_ptr 代表的是共享所有权,即多个 shared_ptr 可以共享同一块内存。
auto wA = shared_ptr<int>(new int(20));
{
auto wA2 = wA;
cout << ((wA2.get() != nullptr) ? (*wA2.get()) : -1) << endl; // 20
cout << ((wA.get() != nullptr) ? (*wA.get()) : -1) << endl; // 20
cout << wA2.use_count() << endl; // 引用计数 :2
cout << wA.use_count() << endl; // 2
} // WA2出了作用域,消亡
//cout << wA2.use_count() << endl;
cout << wA.use_count() << endl; // 1
cout << ((wA.get() != nullptr) ? (*wA.get()) : -1) << endl; // 20
}
- move语法的使用
// move 语法
//将 wAA 对象 move 给 wAA2,意味着 wAA 放弃了对内存的所有权和管理,此时 wAA对象等于 nullptr。
//而 wAA2 获得了对象所有权,但因为此时 wAA 已不再持有对象,因此 wAA2 的引用计数为 1。
auto wAA = std::make_shared<int>(30);
auto wAA2 = std::move(wAA); // 此时 wAA 等于 nullptr,wAA2.use_count() 等于 1
cout << ((wAA.get() != nullptr) ? (*wAA.get()) : -1) << endl; // -1
cout << ((wAA2.get() != nullptr) ? (*wAA2.get()) : -1) << endl; // 30
cout << wAA.use_count() << endl; // 0
cout << wAA2.use_count() << endl;
- 循环引用问题
// demo5-11.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <string>
#include <iostream>
#include <memory>
using namespace std;
// 具有shared_ptr指针的两个结构体
struct B;
struct A {
shared_ptr<B> pb;
~A()
{
cout << "~A()" << endl;
}
};
struct B {
shared_ptr<A> pa;
~B()
{
cout << "~B()" << endl;
}
};
// 具有shared_ptr和weak_ptr指针的两个结构体
struct BW;
struct AW
{
shared_ptr<BW> pb;
~AW()
{
cout << "~AW()" << endl;
}
};
struct BW
{
weak_ptr<AW> pa;
~BW()
{
cout << "~BW()" << endl;
}
};
// pa 和 pb 存在着循环引用,根据 shared_ptr 引用计数的原理,pa 和 pb 都无法被正常的释放。
// weak_ptr 是为了解决 shared_ptr 双向引用的问题。
void Test()
{
cout << "Test shared_ptr and shared_ptr: " << endl;
shared_ptr<A> tA(new A()); // 1
shared_ptr<B> tB(new B()); // 1
cout << tA.use_count() << endl;
cout << tB.use_count() << endl;
tA->pb = tB;
tB->pa = tA;
cout << tA.use_count() << endl; // 2
cout << tB.use_count() << endl; // 2
}
void Test2()
{
cout << "Test weak_ptr and shared_ptr: " << endl;
shared_ptr<AW> tA(new AW());
shared_ptr<BW> tB(new BW());
cout << tA.use_count() << endl; // 1
cout << tB.use_count() << endl; // 1
tA->pb = tB;
tB->pa = tA;
cout << tA.use_count() << endl; // 1,weak_ptr指向tA,不会对tA的引用计数产生影响
cout << tB.use_count() << endl; // 2
} // 当作用域结束后,Aw计数只有1,减一为0后,会正常释放,Aw消亡后,对BW的影响也消除
int main()
{
Test();
Test2();
return 0;
}
2. 引用
为何使用引用
引用的使用
- 测试
// demo5-12.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <assert.h>
using namespace std;
// 编写一个函数,输入两个int型变量a,b
// 实现在函数内部将a,b的值进行交换。
void swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
void swap2(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
// 交换变量的测试
int a = 3, b = 4;
swap(a, b);
assert(a == 4 && b == 3);
a = 3, b = 4;
swap2(&a, &b); // 用指针变量,需要传地址
assert(a == 4 && b == 3);
return 0;
}