Appearance
原始指针
raw pointer
最常用的还是裸指针,其次才是智能指针,因为原始指针很多时候更加方便
智能指针
智能指针在C++ 11中引入,使得C++使用者不需要手动释放内存
⚠️auto_ptr 已经被废弃
智能指针只能解决一部分问题——独占/共享所有权指针的释放、传输,但没有从根本上解决C++的内存安全问题
unique_ptr
在任意给定时刻,智能有一个指针管理内存,推荐通过
std::make_unique实现
- 指针超出作用域,内存将自动释放
- 该类型指针不可以copy,只可以move
- 可以通过get方法获取地址
- 实现了
->和*
cpp
#include <iostream>
#include <string>
#include <memory>
// Define a Class
class Person {
public:
Person(std::string name);
Person() = default;
void print_name() {
std::cout<< "Person Name:" << name <<std::endl;
}
std::string get_person_name(){
return name;
}
void set_person_name(const std::string &name){
this->name = name;
}
private:
std::string name{"A"};
};
// Define a Function
void t_pass_value_func(std::unique_ptr<Person> person){
person->print_name();
}
// const 修饰 person的地址
void t_pass_value_ref_func(const std::unique_ptr<Person> & person){
person->set_person_name("beta");
person->print_name();
std::cout<< "ref address" << person.get() << std::endl;
// person.reset() 由于const,reset会报错
// 且reset会导致外部无法实例的类内调用方法,因为指针地址已经reset
}
// Main Func
int main(int argc, char *agrv[]){
// 使用 make_unique 创建 unique_ptr (C++ 14)
std::unique_ptr<int> i_num = std::make_unique<int> (100);
// 使用 * 解引用
std::cout << * i_num <<std::endl;
// 使用 get() 方法获得指针的地址
std::cout << "i_num address:" << i_num.get() <<std::endl;
// 使用 -> 类内方法
std::unique_ptr<Person> person_a = std::make_unique<Person>();
person_a -> set_person_name("alpha");
person_a -> print_name();
// 所有权转移至函数内部,外部再调用会报错
t_pass_value_func(std::move(person_a));
// person_a -> print_name(); // 生命周期结束,无法调用,程序崩溃
std::unique_ptr<Person> person_b = std::make_unique<Person>();
t_pass_value_ref_func(person_b);
return 0;
}shared_ptr
创建了一个计数器,与类内对象所指向的内存关联
- copy则计数器 +1 , 销毁则计数器 -1
- 计数器API为
use_count()
cpp
#include <iostream>
#include <string>
#include <memory>
void t_pass_value_func(std::shared_ptr<int> i_num){
// use_count() 计数器会 +1 ,因为使用了copy
*i_num = 30;
std::cout << "use count: " << i_num.use_count() << std::endl;
}
void t_pass_ref_func(const std::shared_ptr<int> &i_num){
// use_count() 计数器会 不变 ,因为使用了 const 及 &, const也是限定了无法 reset()
*i_num = 40;
std::cout << "use count: " << i_num.use_count() << std::endl;
}
// Main Func
int main(int argc, char *agrv[]){
std::shared_ptr<int> i_num = std::make_shared<int> (10);
std::cout << "* i_num: " << * i_num << std::endl;
std::cout << "use count: " << i_num.use_count() << std::endl;
std::shared_ptr<int> i_num_copy = i_num;
std::cout << "use count: " << i_num.use_count() << std::endl;
std::cout << "use count: " << i_num_copy.use_count() << std::endl;
// change
*i_num_copy = 20;
std::cout << "* i_num: " << * i_num << std::endl;
std::cout << "* i_num_copy: " << * i_num_copy << std::endl;
// i_num = nullptr; ==> i_num_copy.use_count() 返回 1,i_num.use_count() 返回 0
// i_num_copy = nullptr; ==> i_num.use_count() 返回 1,i_num_copy.use_count() 返回 0
std::cout << "use count: " << i_num.use_count() << std::endl;
std::cout << "use count: " << i_num_copy.use_count() << std::endl;
t_pass_value_func(i_num); // 会在use count输出 3
std::cout << "use count: " << i_num.use_count() << std::endl;
std::cout << "use count: " << i_num_copy.use_count() << std::endl;
std::cout << "* i_num: " << * i_num << std::endl; // 值也会改变
t_pass_ref_func(i_num); // 会在use count输出 2
std::cout << "use count: " << i_num.use_count() << std::endl;
std::cout << "use count: " << i_num_copy.use_count() << std::endl;
std::cout << "* i_num: " << * i_num << std::endl; // 值也会改变
return 0;
}- unique_ptr 可以通过
std::move转化为 shared_ptr ,反之则不行 - 函数返回指针时更推荐使用unique_ptr作为返回类型,可以随时将其改变为shared_ptr
cpp
#include <iostream>
#include <string>
#include <memory>
// return unique_ptr func
std::unique_ptr<int> t_get_unique_ptr(){
std::unique_ptr<int> tmp = std::make_unique<int>(-1);
return tmp;
}
// Main Func
int main(int argc, char *agrv[]){
std::unique_ptr<int> i_unique_num = std::make_unique<int>(10);
std::shared_ptr<int> i_shared_num = std::move(i_unique_num);
std::cout << "* i_shared_num: " << * i_shared_num << std::endl;
std::cout << "use count: " << i_shared_num.use_count() << std::endl;
//t_func
std::shared_ptr<int> t_func = t_get_unique_ptr();
if(t_func){
std::cout << "* t_func: " << * t_func << std::endl;
std::cout << "use count: " << t_func.use_count() << std::endl;
}
return 0;
}weak_ptr
- 循环依赖问题
- 可以通过
lock()函数提升为shared_ptr
cpp
#include <iostream>
#include <string>
#include <memory>
// Define a Class
class Person {
public:
Person(std::string name);
Person() = default;
void print_name() {
std::cout<< "Person Name:" << name <<std::endl;
}
std::string get_person_name(){
return name;
}
void set_person_name(const std::string &name){
this->name = name;
}
void set_friend(std::shared_ptr<Person> person){
__friend = person;
}
private:
std::string name{"A"};
//std::shared_ptr<Person> __friend;
std::weak_ptr<Person> __friend; // 解决循环引用
};
// Main Func
int main(int argc, char *agrv[]){
std::shared_ptr<int> i_shared_num = std::make_shared<int> (10);
std::weak_ptr<int> i_weak_num(i_shared_num);
std::cout << "use count: " << i_shared_num.use_count() << std::endl;//引用计数不变
std::cout << "use count: " << i_weak_num.use_count() << std::endl;//引用计数不变
// 通过lock()转化为shared_ptr
std::shared_ptr<int> i_back_shared_num = i_weak_num.lock();
std::cout << "use count: " << i_weak_num.use_count() << std::endl;//+1
std::cout << "use count: " << i_shared_num.use_count() << std::endl;// +1
std::cout << "use count: " << i_back_shared_num.use_count() << std::endl;// +1
// 循环依赖
std::shared_ptr<Person> person_a = std::make_shared<Person>("person_a");
std::shared_ptr<Person> person_b = std::make_shared<Person>("person_b");
person_a->set_friend(person_b);
person_b->set_friend(person_a);
return 0;
}