Skip to content

原始指针

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;
}
  1. unique_ptr 可以通过 std::move转化为 shared_ptr ,反之则不行
  2. 函数返回指针时更推荐使用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;
}