智能指针Smart Pointer

1.智能指针

  • std::unique_ptr(single ownership)
  • std::shared_ptr(shared ownership)
  • std::weak_ptr(temp/no ownership)
  • C++11以后出现
  • 定义在头文件<memory>

1.0 为啥要有智能指针?

普通指针

void bar(Entity* e)
{
    
    
	// who owns e
	// How long is e's life cycle?
	// Should I delete e?
}
void foo()
{
    
    
	Entity *e = new Entity();
	e->DoSomething();
	bar(e);
}
foo();
// out of scope, memory leak

智能指针

void bar(Entity* e)
{
    
    
	// bar owns e
	// e will be automatically destroyed
}
void foo()
{
    
    
	std::unique_ptr<Entity> e = std::make_unique<Entity>();
	e->DoSomething();
	bar(std::move(e));
}
foo();
// No memory leak

1.1 std::unique_ptr

  • std::unique_ptr<Entity> e1 = new Entity(); // non-assignable
  • std::unique_ptr<Entity> e1(new Entity()); // ok
  • std::unique_ptr<Entity> e1 = std::make_unique<Entity>(); // preferred
  • auto e2 = std::make_unique<Entity>(); // preferred
  • std::unique_ptr<Entity> e2 = e1; // non-copyable
  • std::unique_ptr<Entity> e2 = std::move(e1); // movable, transfer ownership
  • foo(std::move(e1)); // transfer ownership
#include <iostream>
#include <memory>
 
class Entity {
    
    
public:
  Entity() {
    
     puts("Entity created!"); }
  ~Entity() {
    
     puts("Entity destroyed!"); }
};
 
void ex1() {
    
    
  puts("--------");
  puts("Entering ex1");
  {
    
    
    puts("Entering ex1::scope1");
    auto e1 = std::make_unique<Entity>();    
    puts("Leaving ex1::scope1");
  }
  puts("Leaving ex1");
}

void foo(std::unique_ptr<Entity>) {
    
    
  puts("Entering foo");
  puts("Leaving foo");
}
 
void ex2() {
    
    
  puts("--------");
  puts("Entering ex2");
  auto e1 = std::make_unique<Entity>();  
  foo(std::move(e1));
  // e1 was destoried.
  puts("Leaving ex2");
}

int main(int argc, char** argv) {
    
    
  ex1();
  ex2();
  return 0;
}

输出

--------
Entering ex1
Entering ex1::scope1
Entity created!
Leaving ex1::scope1
Entity destroyed!
Leaving ex1
--------
Entering ex2
Entity created!
Entering foo
Leaving foo
Entity destroyed!
Leaving ex2

1.2 std::shared_ptr

  • std::shared_ptr<Entity> e1(new Entity()); // ok
  • std::shared_ptr<Entity> e1 = std::make_shared<Entity>(); // preferred
  • auto e2 = std::make_shared<Entity>(); // preferred
  • std::shared_ptr<Entity> e2 = e1; // copyable, use_count + 1
  • std::shared_ptr<Entity> e2 = std::move(e1); // movable, use_count remains
  • foo(e1); // use_count + 1
  • foo(std::move(e1)); // use_count remains
#include <iostream>
#include <memory>
 
class Entity {
    
    
public:
  Entity() {
    
     puts("Entity created!"); }
  ~Entity() {
    
     puts("Entity destroyed!"); }
};
 
void ex3() {
    
    
  puts("--------");
  puts("Entering ex3");
  auto e1 = std::make_shared<Entity>();
  std::cout << e1.use_count() << std::endl;
  {
    
    
    puts("Entering ex3::scope1");
    auto e2 = e1; // use_count ++
    std::cout << e1.use_count() << std::endl;
    auto e3 = std::move(e2); // use_count remains
    std::cout << e1.use_count() << std::endl;
    puts("Leaving ex3::scope1");
  }
  std::cout << e1.use_count() << std::endl;
  puts("Leaving ex3");
}

int main(int argc, char** argv) {
    
    
  ex3();
  return 0;
}

输出

--------
Entering ex3
Entity created!
1
Entering ex3::scope1
2
2
Leaving ex3::scope1
1
Leaving ex3
Entity destroyed!

1.3 std::weak_ptr

  • Must be converted to a std::shared_ptr before accessing
  • Models a temporary ownership
    • Access if the object still exist
    • Ok if the object was already destroyed
  • auto e1 = std::make_shared<Entity>();
std::weak_ptr<Entity> ew = e1;  // construct from a shared_ptr`
if (std::shared_ptr<Entity> e2 = ew.lock())  // convert to a shared_ptr
	e2->DoSomething();
#include <iostream>
#include <memory>
 
class Entity {
    
    
public:
  Entity() {
    
     puts("Entity created!"); }
  ~Entity() {
    
     puts("Entity destroyed!"); }
};
 
void observe(std::weak_ptr<Entity> ew) {
    
    
  if (std::shared_ptr<Entity> spt = ew.lock()) {
    
    
    std::cout << spt.use_count() << std::endl;
    std::cout << "entity still alive!" << std::endl;
  } else {
    
    
    std::cout << "entity was expired !" << std::endl;
  }
}
 
void ex4() {
    
    
  puts("--------");
  puts("Entering ex4");
  std::weak_ptr<Entity> ew;  
  {
    
    
    puts("Entering ex4::scope1");
    auto e1 = std::make_shared<Entity>();
    std::cout << e1.use_count() << std::endl;
    ew = e1; // use_count remains
    std::cout << e1.use_count() << std::endl;
    observe(ew);
    puts("Leaving ex4::scope1");
  }
  observe(ew);
  puts("Leaving ex4");
}
 
int main(int argc, char** argv) {
    
    
  ex4();
  return 0;
}

输出

--------
Entering ex4
Entering ex4::scope1
Entity created!
1
1
2
entity still alive!
Leaving ex4::scope1
Entity destroyed!
entity was expired !
Leaving ex4

总结

  • 能用智能指针就用智能指针,不再使用new/delete
  • 能用std::unique_ptr 就不用std::shared_ptr
  • 尽量使用move std::shared_ptr

参考目录

https://zxi.mytechroad.com/blog/c/cpp-11-smart-pointers/

猜你喜欢

转载自blog.csdn.net/weixin_43229348/article/details/124577184