C++ Primer: 内存管理

1. new 和 delete

在C++中,内存管理是一个核心且复杂的主题,它涉及到动态内存分配和释放。newdelete操作符是C++中用于管理动态内存的主要工具。

1.1 new

new操作符用于在堆上动态分配内存,并调用对象的构造函数(如果有的话)。new可以返回指向分配的内存的指针,该指针可以用来访问和操作对象。

例子
#include <iostream>
using namespace std;

class MyClass {
public:
    MyClass(int x) : value(x) {}
    void display() const {
        cout << "Value: " << value << endl;
    }
private:
    int value;
};

int main() {
    // 使用new动态分配MyClass对象
    MyClass* myObject = new MyClass(10);

    // 使用对象
    myObject->display();  // 输出: Value: 10

    // ...(后续对myObject的操作)

    // 不要忘记释放内存
    delete myObject;

    return 0;
}

在这个例子中,new操作符被用来在堆上分配一个MyClass类型的对象,并调用其构造函数,传递参数10。分配的内存地址被存储在指针myObject中,然后通过该指针访问对象的display方法。

1.2 delete

delete操作符用于释放之前通过new操作符分配的内存。当使用delete时,对象的析构函数(如果有的话)会被调用,以执行必要的清理工作。

例子(继续上面的代码)
// ...(前面的代码)

// 释放内存
delete myObject;

// 注意:释放内存后,myObject成为悬垂指针(dangling pointer),
// 它不再指向有效的内存地址。为了安全起见,可以将它设置为nullptr。
myObject = nullptr;

// 尝试访问已删除的对象会导致未定义行为
// myObject->display();  // 不要这样做!

return 0;

在这个例子中,delete操作符被用来释放myObject指针所指向的内存。在释放内存后,将myObject设置为nullptr是一个好习惯,这可以防止悬垂指针的问题。

注意事项
  • 匹配new和delete:对于每个new表达式,都应该有一个对应的delete表达式。同样,对于new[](用于分配对象数组),应该使用delete[]来释放内存。
  • 避免内存泄漏:确保所有通过new分配的内存最终都被delete释放。内存泄漏是程序长期运行后性能下降的常见原因之一。
  • 避免重复释放:不要对同一个指针使用多次delete。这会导致未定义行为,通常表现为程序崩溃。
  • 智能指针:C++11及更高版本引入了智能指针(如std::unique_ptrstd::shared_ptr),它们可以自动管理内存,减少内存泄漏的风险。

通过合理使用newdelete(或智能指针),C++程序员可以精确控制程序的内存使用,编写出高效、可维护的代码。

2. 智能指针

在C++中,智能指针是管理动态内存的一种重要方式,它们能够自动释放所管理的资源,从而避免内存泄漏等问题。以下是关于智能指针的详细整理,包括通用操作、shared_ptr、unique_ptr和weak_ptr,并附有具体例子。

2.1 智能指针的通用操作

智能指针的行为类似于常规指针,但它们提供了自动资源管理的功能。智能指针一般支持以下几种通用操作:

  • 解引用:使用*运算符可以解引用智能指针,获得其所指向的对象。
  • 成员访问:使用->运算符可以访问智能指针所指向对象的成员。
  • 条件判断:在条件判断中使用智能指针时,会检查它是否为空。
2.2 shared_ptr

shared_ptr是一种智能指针,它允许多个shared_ptr实例共享对同一个对象的所有权。当最后一个shared_ptr被销毁或重置时,它所管理的对象也会被自动销毁。

2.2.1 创建与赋值
#include <memory>
#include <iostream>

int main() {
    std::shared_ptr<int> p1 = std::make_shared<int>(42); // 使用make_shared创建
    std::shared_ptr<int> p2 = p1; // 赋值,共享所有权

    std::cout << *p1 << std::endl; // 输出: 42
    std::cout << *p2 << std::endl; // 输出: 42

    return 0;
}
2.2.2 自定义删除器

shared_ptr允许你指定一个自定义的删除器,该删除器在对象被销毁时调用。

#include <memory>
#include <iostream>

void customDeleter(int* p) {
    delete p;
    std::cout << "Custom deleter called" << std::endl;
}

int main() {
    std::shared_ptr<int> p(new int(42), customDeleter);
    // ...
    return 0; // 当p被销毁时,customDeleter被调用
}
2.3 unique_ptr

unique_ptr是一种“独占”的智能指针,它在任何时候都只能有一个unique_ptr指向一个给定的对象。一旦unique_ptr被销毁,它所管理的对象也会被销毁。

2.3.1 初始化与赋值
#include <memory>
#include <iostream>

int main() {
    std::unique_ptr<int> p1(new int(42)); // 初始化
    // std::unique_ptr<int> p2 = p1; // 错误:不支持拷贝赋值

    // 所有权转移
    std::unique_ptr<int> p3;
    p3 = std::move(p1); // 现在p3拥有对象,p1为空

    std::cout << *p3 << std::endl; // 输出: 42

    return 0;
}
2.3.2 自定义删除器

unique_ptr同样支持自定义删除器。

#include <memory>
#include <iostream>

void customDeleter(int* p) {
    delete p;
    std::cout << "Custom deleter called" << std::endl;
}

int main() {
    std::unique_ptr<int, void(*)(int*)> p(new int(42), customDeleter);
    // ...
    return 0; // 当p被销毁时,customDeleter被调用
}
2.4 weak_ptr 解决循环引用

weak_ptr是一种不拥有其所指向对象所有权的智能指针,它通常与shared_ptr一起使用来解决循环引用问题。

2.4.1 循环引用问题

当两个或多个shared_ptr相互引用时,它们会形成循环引用,导致对象无法被正确销毁。

2.4.2 使用weak_ptr解决循环引用
#include <memory>
#include <iostream>

class A;
class B;

class A {
public:
    std::shared_ptr<B> b_ptr;
    // ...
};

class B {
public:
    std::weak_ptr<A> a_wptr;
    // ...
};

int main() {
    std::shared_ptr<A> a = std::make_shared<A>();
    std::shared_ptr<B> b = std::make_shared<B>();

    a->b_ptr = b;
    b->a_wptr = a;

    // ...
    // 当a和b被销毁时,由于a_wptr不拥有b的所有权,所以b可以被正确销毁
    // 然后a也可以被销毁,避免了循环引用导致的内存泄漏

    return 0;
}

在上面的例子中,A类包含一个指向Bshared_ptr,而B类包含一个指向Aweak_ptr。这样,即使存在相互引用,也不会形成循环引用问题,因为weak_ptr不增加shared_ptr的引用计数。当shared_ptr被销毁时,如果没有其他shared_ptr指向该对象,则对象会被自动销毁,此时weak_ptr也会变为空。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TrustZone_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值