cplusplus指针与引用
智能指针
- 智能指针分类: std::unique_ptr, std::shared_ptr, std::weak_ptr.使用它们需要包含头文件
<memory>. - std::unique_ptr 是独占所有权的智能指针, 确保同一时间只能有一个 unique_ptr指向对象. 不能进行拷贝操作,但是可以通过移动操作将所有权转移给其它指针.
- std::shared_ptr 允许多个指针共享同一个对象的所有权,通过引用计数来管理共享资源,当最后一个指向该对象的指针被销毁时,对象会被自动释放.
- std::weak_ptr 是一种弱引用的智能指针, 不拥有对象的所有权, 不会影响对象的生命周期,通常用于解决循环引用问题.配合 std::shared_ptr 的使用,解决循环引用的问题.
- std::auto_ptr 是C++98标准引入的智能指针, 也实现了对对象的独占所有权, 但在复制操作时会移动资源.在C++11中被废弃.
- C++11 新增了 std::make_shared() 方法创建一个 std::shared_ptr 对象,却没有提供相应的 std::make_unique() 方法创建一个 std::unique_ptr 对象,这个方法直到 C++14 才被添加进来.
std::unique_ptr
std::shared_ptr
std::weak_ptr
std::auto_ptr
#include <iostream>
#include <memory>
#include <string>
// 一个简单的类,用来观察构造和析构
class Person {
public:
Person(const std::string& name) : name_(name) {
std::cout << "构造 Person: " << name_ << "\n";
}
~Person() {
std::cout << "析构 Person: " << name_ << "\n";
}
void sayHello() const {
std::cout << "Hello, I am " << name_ << "\n";
}
private:
std::string name_;
};
// 接受 unique_ptr 的函数(通过移动)
void greet(std::unique_ptr<Person> p) {
p->sayHello();
}
int main() {
// 1. 创建 unique_ptr
std::unique_ptr<Person> p1 = std::make_unique<Person>("Alice");
p1->sayHello();
// 2. 转移所有权(move)
std::unique_ptr<Person> p2 = std::move(p1);
if (!p1) {
std::cout << "p1 已经失去所有权\n";
}
p2->sayHello();
// 3. 将 unique_ptr 传递给函数(必须使用 std::move)
greet(std::move(p2));
if (!p2) {
std::cout << "p2 也失去所有权了\n";
}
// 4. 自定义删除器
auto deleter = [](Person* p) {
std::cout << "使用自定义删除器释放 Person\n";
delete p;
};
std::unique_ptr<Person, decltype(deleter)> p3(new Person("Bob"), deleter);
p3->sayHello();
// main 结束时,p3 会自动调用自定义删除器
return 0;
}
/**
Output:
构造 Person: Alice
Hello, I am Alice
p1 已经失去所有权
Hello, I am Alice
Hello, I am Alice
析构 Person: Alice
p2 也失去所有权了
构造 Person: Bob
Hello, I am Bob
使用自定义删除器释放 Person
析构 Person: Bob
*/
#include <iostream>
#include <memory>
#include <string>
class Person {
public:
Person(const std::string& name) : name_(name) {
std::cout << "构造 Person: " << name_ << "\n";
}
~Person() {
std::cout << "析构 Person: " << name_ << "\n";
}
void sayHello() const {
std::cout << "Hello, I am " << name_ << "\n";
}
private:
std::string name_;
};
int main() {
// 1. 创建 shared_ptr
std::shared_ptr<Person> p1 = std::make_shared<Person>("Alice");
std::cout << "p1.use_count = " << p1.use_count() << "\n";
{
// 2. 复制 shared_ptr(引用计数 +1)
std::shared_ptr<Person> p2 = p1;
// use_count() 用来返回当前共享同一对象的 shared_ptr 的数量.
std::cout << "p1.use_count = " << p1.use_count() << "\n";
std::cout << "p2.use_count = " << p2.use_count() << "\n";
p2->sayHello();
} // p2 离开作用域,引用计数 -1
std::cout << "p1.use_count = " << p1.use_count() << "\n";
// 3. 自定义删除器
auto deleter = [](Person* p) {
std::cout << "使用自定义删除器释放 Person\n";
delete p;
};
std::shared_ptr<Person> p3(new Person("Bob"), deleter);
std::cout << "p3.use_count = " << p3.use_count() << "\n";
p3->sayHello();
// 4. 使用 weak_ptr 观察 shared_ptr(不增加引用计数)
std::weak_ptr<Person> wp = p3;
std::cout << "p3.use_count = " << p3.use_count() << "\n";
// expired() 用来判断 weak_ptr 所观察的对象是否已经被销毁.
std::cout << "wp.expired = " << wp.expired() << "\n";
// 5. 通过 weak_ptr 获取 shared_ptr
if (auto sp = wp.lock()) {
sp->sayHello();
std::cout << "sp.use_count = " << sp.use_count() << "\n";
}
return 0;
}
指针与引用的区别
| 特性 | 指针 | 引用 |
|---|---|---|
| 声明 | int* p; |
int& ref = a; |
| 初始化 | 可不初始化,默认为野指针 | 必须初始化 |
| 使用时访问变量值 | 需要解引用 *p |
直接使用 ref |
| 重新赋值 | 指针可以指向不同地址 | 引用一旦绑定不可更改 |
| 空指针 | 可以指向空(nullptr) |
引用不能为“空”,必须绑定有效对象 |
- 指针 指针是一个变量,存储的是另一个变量的内存地址。指针可以指向任何数据类型,包括基本类型、对象、函数等。实质是存储地址的变量,占用内存空间(通常是4或8字节,依赖于系统架构)。
- 引用 引用是某个变量的别名,是已存在变量的一个别称。引用必须在定义时初始化,且一旦绑定到某个变量,就不能再绑定到其它变量。引用通常被实现为指针的常量别名,编译器在生成代码时会优化为直接访问目标变量,引用本身不占用额外空间。
指针与引用代码示例
#include <iostream>
void incrementPointer(int* p) {
if (p) {
(*p)++;
}
}
void incrementReference(int& r) {
r++;
}
int main() {
int a = 5;
incrementPointer(&a);
std::cout << "After incrementPointer: " << a << std::endl; // 输出6
incrementReference(a);
std::cout << "After incrementReference: " << a << std::endl; // 输出7
return 0;
}
函数指针
函数指针代码示例
/**
* 深入理解 int (*(*fp)(int (*)(int, int), int))(int, int)
1. 参数:
(*fp)(int (*)(int, int), int)
fp 是一个函数指针,指向的函数有两个参数:
第一个参数:int (*)(int, int), 一个函数指针,指向返回 int,参数为 (int, int) 的函数。
例如:int add(int a, int b) 或 int mul(int a, int b)。
第二个参数:int.
2. 返回部分:
返回部分
(*fp)(...) 的返回值是:
int (*)(int, int)
即一个函数指针,指向返回 int,参数为 (int, int) 的函数。
换句话说,fp 所指向的函数会返回一个函数指针,这个函数指针本身可以再被调用。
*/
#include <stdio.h>
// 定义一个函数指针类型,指向返回 int,参数为 (int, int) 的函数
// 代表: int (*)(int, int)
typedef int (*func2_t)(int, int);
// 一个简单的函数,符合 func2_t 类型
int add(int a, int b) {
return a + b;
}
int mul(int a, int b) {
return a * b;
}
// 定义一个函数,符合 fp 的签名:
// 参数:一个 func2_t 和一个 int
// 返回:一个 func2_t
// 代表: (*fp)(int (*)(int, int), int)
func2_t chooser(func2_t f, int flag) {
if (flag == 0) {
return add;
} else {
return mul;
}
}
int main() {
/**
* 声明 fp
* 类似于:
* typedef int (*func2_t)(int, int); // 二元函数指针类型
* typedef func2_t (*fp_t)(func2_t, int); // 返回 func2_t,参数为 (func2_t, int) 的函数指针类型
* fp_t fp; // fp 就是这种函数指针
*/
int (*(*fp)(int (*)(int, int), int))(int, int);
// 让 fp 指向 chooser
fp = chooser;
// 使用 fp:传入 add 和一个 flag,得到返回的函数指针
func2_t f1 = fp(add, 0); // 返回 add
func2_t f2 = fp(add, 1); // 返回 mul
printf("f1(3,4) = %d\n", f1(3,4)); // 3+4 = 7
printf("f2(3,4) = %d\n", f2(3,4)); // 3*4 = 12
return 0;
}
/**
output:
f1(3,4) = 7
f2(3,4) = 12
*/