智能指针
智能指针
-
指针
注1
管理的困境是什么-
资源释放了但是指针没有为空
-
野指针:野指针是指指向未知内存地址的指针,也就是没有初始化或者已经被释放的指针。使用野指针会导致程序崩溃、内存泄漏等严重问题。(单个指针)
int *ptr;{ int x = 5; ptr = &x;} // `x` 已经被释放,`ptr` 成为了野指针 std::cout << *ptr << std::endl; // 会导致未定义行为
-
指针悬挂:是指当指向的内存被释放或者销毁后,指针仍然指向该内存地址,此时使用该指针会导致未定义行为。指针悬挂通常是由于程序员未及时清除指针,或者指针被错误地释放导致的。(通常是多个指针指向同一个资源)
int *get_pointer() {int i = 42; int *p = &i; return p;} int main() { int *p = get_pointer(); // p 是悬挂指针,指向的内存已经被释放 return 0;}
-
踩内存:踩内存指的是程序错误地访问了未分配给它的内存空间,通常会导致程序崩溃或不可预测的行为。(内存已经被其他地方占用,虽然确实是一个合法的内存)
int main() { int* p; *p = 1; // 试图给未分配的指针指向的内存赋值 return 0;} //在这个例子中,指针 p 没有分配任何内存空间,而在代码中却试图通过 *p 来访问它所指向的内存。这样的行为通常会导致程序崩溃或者出现不可预测的错误,因为指针 p 所指向的内存空间是未知的,可能已经被其他程序或系统占用了。
-
-
没有释放资源产生内存泄漏(没有delete释放资源)
-
重复释放资源,引发coredump
-
-
怎么解决的指针管理的困境?
-
运用RAII思想:它利用了C++的对象生命周期和构造/析构函数来自动管理资源,避免了程序中因资源泄露而导致的安全隐患和资源浪费问题。
-
具体方法是将资源的分配和释放封装在一个对象的构造函数和析构函数中,对象的生命周期与资源的分配和释放相对应,确保了资源的正确释放。
class MyClass { public: MyClass() { std::cout << "MyClass constructor" << std::endl; } ~MyClass() { std::cout << "MyClass destructor" << std::endl; } void doSomething() { std::cout << "MyClass doSomething" << std::endl; } }; int main() { std::unique_ptr<MyClass> ptr(new MyClass); ptr->doSomething(); return 0; } //在这个示例中,我们使用了一个std::unique_ptr智能指针来管理MyClass对象的内存,当std::unique_ptr对象超出其作用域时,它的析构函数会自动释放它所管理的内存,这样就不需要手动释放内存,避免了内存泄漏等问题。这种使用智能指针的方法是RAII思想的体现,它可以保证程序的安全性和效率。
-
-
-
智能指针的种类(智能指针是一种 C++ 的语言特性,其可以在一定程度上解决程序中内存泄漏和多次释放同一块内存等问题。)
- unique_ptr:独占式智能指针,只能有一个指针指向同一块内存,当指针被销毁时,内存也被自动释放。
- shared_ptr:共享式智能指针,多个指针可以指向同一块内存,内存会在最后一个指针被销毁时释放。
- 解决了指针悬挂
- weak_ptr:弱引用智能指针,是对 shared_ptr 的补充,可以观察 shared_ptr 是否被释放。(怎么解决weak_ptr循环引用问题)
- auto_ptr:C++11 之前的独占式智能指针,已被 unique_ptr 取代。
注1
在计算机程序中,指针(pointer)是一个变量,用来存储另一个变量的地址。我们可以通过指针来访问或修改对应地址上存储的值。
int main() {
int x = 10;
int *p = &x; // 声明一个指针变量p,并将其初始化为变量x的地址
cout << "x 的值为:" << x << endl; // 输出 x 的值
cout << "p 指向的变量的值为:" << *p << endl; // 输出 p 指向的变量的值
*p = 20; // 通过指针修改变量 x 的值
cout << "x 的新值为:" << x << endl; // 输出修改后的 x 的值
return 0;
}
//在上述示例中,我们首先声明了一个 int 类型的变量 x,并将其初始化为 10。然后,我们声明了一个指针变量 p,并将其初始化为 x 的地址。通过使用 *p 访问 p 指向的变量的值,我们输出了变量 x 的值。接下来,我们使用 *p 修改了变量 x 的值为 20,并再次输出了修改后的 x 的值。