C++中智能指针学习(shared_ptr、unique_ptr)

智能指针学习

相关理论

参考:

智能指针是 C++ 中一种资源管理工具,主要用于管理动态分配的内存。当你使用 new 关键字分配了一个对象并希望在不需要该对象时能够自动回收它时,你就可以使用智能指针。————chatGPT

例如,假设我们有一个对象:

class SomeClass {
public:
  SomeClass(int x) : data(x) {}
  int data;
};

如果我们不使用智能指针,创建一个该对象的实例并将其存储在普通指针中,可能会如下所示:

SomeClass *ptr = new SomeClass(42);
// ...
delete ptr;

但是,如果在代码中出现了异常或错误,或者忘记调用 delete,则可能会导致内存泄漏。

使用智能指针时,代码可能如下所示:

std::unique_ptr<SomeClass> ptr(new SomeClass(42));
// ...

在这种情况下,我们不需要手动调用 delete,因为智能指针在其生命周期结束时会自动回收对象。这可以帮助避免内存泄漏和管理资源的错误。

关于智能指针的使用,还有几个重要的点。

  1. 首先,C++ 中有几种不同类型的智能指针,如 std::unique_ptr 和 std::shared_ptr。它们的主要区别在于它们如何处理多个指针共享相同的对象。

  2. std::unique_ptr 表示所有权,它是对象的唯一所有者。这意味着,一旦该对象被赋值给另一个 std::unique_ptr,原来的智能指针将不再持有该对象。

  3. std::shared_ptr 允许多个智能指针共享同一对象,并且对象的生命周期取决于最后一个指向该对象的智能指针是否仍然存在。

  4. 另一方面,智能指针还可以用于管理需要特殊处理的对象,例如文件句柄、线程等。在这种情况下,智能指针的析构函数可以用于自动关闭文件或终止线程。

因此,使用智能指针是一种很好的 C++ 资源管理技巧,可以帮助消除内存泄漏、简化代码、避免资源管理错误,并且可以对需要特殊处理的对象进行管理。

shared_ptr代码案例

#include <iostream>
#include <memory> // 需要包含这个头文件

/* 
* shared_ptr 自带删除器
* 当 shared_ptr 对象超出范围时,将调用其析构函数。
* 在其析构函数中,它将引用计数减1,如果引用计数的新值为0,则删除关联的原始指针。
* 析构函数中删除内部原始指针,默认调用的是delete()函数。 
*/
static void example1() {
	// 使用 make_shared 创建空对象
	std::shared_ptr<int> p1 = std::make_shared<int>();	// 初始化为0

	// 第一次使用

	*p1 = 78;

	std::cout << "p1 = " << *p1 << std::endl; // 输出78

	// 打印引用个数:1
	std::cout << "p1 Reference count = " << p1.use_count() << std::endl;

	// 第2个 shared_ptr 对象指向同一个指针
	std::shared_ptr<int> p2(p1);

	// 下面两个输出都是:2
	std::cout << "p2 Reference count = " << p2.use_count() << std::endl;
	std::cout << "p1 Reference count = " << p1.use_count() << std::endl;

	// 比较智能指针,p1 等于 p2
	if (p1 == p2) {
		std::cout << "p1 and p2 are pointing to same pointer\n";
	}

	std::cout<<"Reset p1 "<<std::endl;

	// 无参数调用reset,无关联指针,引用个数为0
	p1.reset();
	std::cout << "p1 Reference Count = " << p1.use_count() << std::endl;
	
	// 带参数调用reset,引用个数为1
	p1.reset(new int(11));
	std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;

	// 把对象重置为NULL,引用计数为0
	p1 = nullptr;
	std::cout << "p1  Reference Count = " << p1.use_count() << std::endl;
	if (!p1) {
		std::cout << "p1 is NULL" << std::endl; // 输出
	}
}

struct Sample {
    Sample() {
        std::cout << "Sample\n";
    }
    ~Sample() {
        std::cout << "~Sample\n";
    }
};

void deleter(Sample * x) {
    std::cout << "Custom Deleter\n";
    delete[] x;
}

/*
* 自定义删除器,主要用于数值等指针的删除
*/
static void example2() {
    std::shared_ptr<Sample> p3(new Sample[3], deleter);
}

struct Sample2 {
	void dummyFunction() {
		std::cout << "dummyFunction" << std::endl;
	}
};

/* 与普通指针相比,shared_ptr仅提供-> 、*和==运算符,没有+、-、++、--、[]等运算符。 */

static void example3() {
	std::shared_ptr<Sample2> ptr = std::make_shared<Sample2>();

	(*ptr).dummyFunction(); // 正常
	ptr->dummyFunction(); // 正常

	// ptr[0]->dummyFunction(); // 错误方式
	// ptr++;  // 错误方式
	// ptr--;  // 错误方式

	std::shared_ptr<Sample2> ptr2(ptr);
	if (ptr == ptr2) // 正常
		std::cout << "ptr and ptr2 are equal" << std::endl;
}

// 主函数
int main()
{
	example1();
	example2();
	example3();
	return 0;
}
/* std::shared_ptr 是 C++ 标准库中的一种智能指针,它允许多个指针共享同一对象。
* 它维护一个引用计数,并在所有对该对象的引用都已经释放后,自动释放该对象。 */

#include <memory>       // C++ 11内置智能指针
#include <iostream>

/*********************************************example1*********************************************/
class Foo {
 public:
  Foo() {
    std::cout << "Foo created." << std::endl;
  }

  ~Foo() {
    std::cout << "Foo destroyed." << std::endl;
  }
};

static void example1() {
  std::shared_ptr<Foo> p1 = std::make_shared<Foo>();
  std::cout << "p1 reference count: " << p1.use_count() << std::endl;

  std::shared_ptr<Foo> p2 = p1;
  std::cout << "p1 reference count: " << p1.use_count() << std::endl;
  std::cout << "p2 reference count: " << p2.use_count() << std::endl;

  p1.reset();
  std::cout << "p2 reference count: " << p2.use_count() << std::endl;
}
/**
 * 作为函数的返回值,避免内存泄漏:
 * *******************************************example2*********************************************/
std::shared_ptr<int> createNumber() {
  return std::make_shared<int>(42);
}
static void example2() {
  auto p = createNumber();
  std::cout << *p << std::endl;
}
/**
 * 作为类成员变量,管理类的生命周期:
 * *******************************************example3*********************************************/
class Bar {
 public:
  Bar(std::shared_ptr<int> p) : pNumber(p) {
    std::cout << "Bar created." << std::endl;
  }

  ~Bar() {
    std::cout << "Bar destroyed." << std::endl;
  }

 private:
  std::shared_ptr<int> pNumber;
};

static void example3() {
  std::shared_ptr<int> p = std::make_shared<int>(42);
  Bar bar(p);
}
/**
 * 作为父类指针,管理多个派生类的生命周期:
 * *******************************************example4*********************************************/
class Base {
 public:
  Base() {
    std::cout << "Base created." << std::endl;
  }

  virtual ~Base() {
    std::cout << "Base destroyed." << std::endl;
  }
};

class Derived1 : public Base {
 public:
  Derived1() {
    std::cout << "Derived1 created." << std::endl;
  }

  ~Derived1() {
    std::cout << "Derived1 destroyed." << std::endl;
  }
};

class Derived2 : public Base {
 public:
  Derived2() {
    std::cout << "Derived2 created." << std::endl;
  }

  ~Derived2() {
    std::cout << "Derived2 destroyed." << std::endl;
  }
};

static void example4() {
  std::shared_ptr<Base> p1 = std::make_shared<Derived1>();
  std::shared_ptr<Base> p2 = std::make_shared<Derived2>();
}

int main() {
  example1();
  example2();
  example3();
  example4();
  return 0;
}

unique_ptr使用案例

#include <memory>
#include <iostream>

/********************************************example1*********************************************/
static void example1() {
  std::unique_ptr<int> p1(new int(42));
  std::cout << *p1 << std::endl;  // 输出 42
}
/********************************************example2*********************************************/
std::unique_ptr<int> make_int(int value) {
  return std::make_unique<int>(value);
}

static void example2() {
  std::unique_ptr<int> ptr = make_int(42);
  std::cout << *ptr << std::endl;  // 输出 42
}
/********************************************example3*********************************************/
class Foo {
public:
  Foo() : ptr_(std::make_unique<int>(42)) {}

  void print() const {
    std::cout << *ptr_ << std::endl;
  }

private:
  std::unique_ptr<int> ptr_;
};
static void example3() {
  Foo foo;
  foo.print();  // 输出 42
}

int main() {
    example1();
    example2();
    example3();
}

欢迎批评指正

猜你喜欢

转载自blog.csdn.net/p3116002589/article/details/129160863
今日推荐