C++11新特性

一、auto关键字

1.自动推导变量类型

2.autodecltype的区别 

auto用于推导变量的类型,而decltype用于推导表达式的类型。

3.auto与范围for循环

std::vector<int> vec = {1, 2, 3, 4};
for (auto element : vec) {
    std::cout << element << " ";
}

4.auto的限制

auto不能用于推导未初始化变量的类型;推导时必须有初始化表达式。

此外,auto无法推导函数参数类型或返回类型的具体形式。 

 二、智能指针——用于自动管理动态分配内存的生命周期

1. std::unique_ptr

主要特点

  1. 独占所有权std::unique_ptr 保证一个对象只有一个所有者,避免了多个智能指针同时管理同一对象的情况。
  2. 自动释放资源:当 std::unique_ptr 超出作用域时,它会自动释放它管理的对象,防止内存泄漏。
  3. 不能复制std::unique_ptr 不允许复制构造和赋值操作,只能通过移动构造和移动赋值来转移所有权。

主要操作

  1. 创建和初始化
     

    std::unique_ptr<int> ptr = std::make_unique<int>(10);
    
    //std::make_unique 是推荐的创建方式,它会返回一个 std::unique_ptr,并且可以避免潜在的异常安全问题。
    
  2. 移动所有权
     

    std::unique_ptr<int> ptr1 = std::make_unique<int>(20);
    std::unique_ptr<int> ptr2 = std::move(ptr1); // ptr1 现在为空,ptr2 拥有所有权
    

  3. 访问和操作对象
     

    //使用 * 操作符来访问和修改 std::unique_ptr 管理的对象。
    
    std::unique_ptr<int> ptr = std::make_unique<int>(30);
    *ptr = 40; // 修改值
    int value = *ptr; // 访问值
    

  4. 释放资源:
     

    std::unique_ptr<int> ptr = std::make_unique<int>(50);
    ptr.reset(); // 释放资源,将 ptr 置为空
    

实际应用示例

  1. 动态数组管理
     

    std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
    for (int i = 0; i < 5; ++i) {
        arr[i] = i * 10;
    }
    
  2. 封装资源管理:确保在对象超出作用域时自动释放资源。

    class Resource {
    public:
        Resource() { /* allocate resources */ }
        ~Resource() { /* release resources */ }
    };
    
    std::unique_ptr<Resource> res = std::make_unique<Resource>();
    
  3. 避免资源泄漏的工厂函数
     

    std::unique_ptr<int> createResource() {
        return std::make_unique<int>(100);
    }
    
    void useResource() {
        std::unique_ptr<int> resource = createResource();
        // 使用 resource
    }
    

2.shared_ptr

是一个引用计数智能指针,允许多个 shared_ptr 实例共享同一个对象的所有权。

它会自动管理对象的生命周期,当最后一个 shared_ptr 离开作用域或被重置时,自动释放对象的内存。

std::shared_ptr 提供了自动内存管理和共享所有权的功能,适用于需要多个所有者的场景。注意避免循环引用以防内存泄漏,适当使用 std::weak_ptr 解决此问题。

主要特点

  1. 引用计数管理std::shared_ptr 使用一个引用计数来追踪有多少个 shared_ptr 实例指向同一个对象。当引用计数变为零时,自动删除对象。
  2. 线程安全:对引用计数的操作是线程安全的,但对象的管理仍需注意线程同步。
  3. 复制和赋值:可以复制和赋值 std::shared_ptr,每个 shared_ptr 都持有一个对同一对象的引用。

基本用法

创建和初始化
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> p1 = std::make_shared<int>(10); // 创建一个 shared_ptr
    std::cout << *p1 << std::endl; // 输出 10
}
复制和赋值
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> p1 = std::make_shared<int>(20);
    std::shared_ptr<int> p2 = p1; // p2 和 p1 共享所有权
    std::cout << *p2 << std::endl; // 输出 20
}
使用 reset 方法
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> p1 = std::make_shared<int>(30);
    p1.reset(); // 释放 p1 持有的对象
    if (!p1) {
        std::cout << "p1 is null" << std::endl;
    }
}
获取底层原始指针

原始指针是 shared_ptr 持有的实际对象的直接指针,但不管理对象的生命周期。使用原始指针时需小心,以避免在智能指针仍在管理对象的情况下误用或误删除该对象。

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> p1 = std::make_shared<int>(40);
    int* rawPtr = p1.get(); // 获取底层原始指针
    std::cout << *rawPtr << std::endl; // 输出 40
}
循环引用问题
#include <iostream>
#include <memory>

struct Node {
    std::shared_ptr<Node> next;
    ~Node() { std::cout << "Node destroyed" << std::endl; }
};

int main() {
    std::shared_ptr<Node> a = std::make_shared<Node>();
    std::shared_ptr<Node> b = std::make_shared<Node>();
    a->next = b;
    b->next = a; // 形成循环引用
    // 这里 a 和 b 都不会被销毁,因为它们互相引用
}

  解决循环引用——使用弱指针

#include <iostream>
#include <memory>

struct Node {
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev; // 使用 weak_ptr 解决循环引用
    ~Node() { std::cout << "Node destroyed" << std::endl; }
};

int main() {
    std::shared_ptr<Node> a = std::make_shared<Node>();
    std::shared_ptr<Node> b = std::make_shared<Node>();
    a->next = b;
    b->prev = a; // 使用 weak_ptr 打破循环引用
}

3.weak_ptr

std::shared_ptr 配合使用,用于解决循环引用问题。std::weak_ptr 不会影响引用计数,因此它不会阻止被指向对象的销毁。 

主要特点

  1. 不影响引用计数std::weak_ptr 只观察一个 std::shared_ptr 指向的对象,但不会增加对象的引用计数。它的存在不会影响对象的生命周期。
  2. 可以转换为 std::shared_ptr:使用 weak_ptr 可以尝试获取一个 shared_ptr 来访问对象,这样可以安全地检查对象是否仍然存在。
  3. 打破循环引用std::weak_ptr 是避免 std::shared_ptr 之间互相持有引用而导致内存泄漏的有效工具。

常见用法

创建和初始化
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(10);
    std::weak_ptr<int> wp = sp; // wp 不会增加引用计数
    std::cout << "shared_ptr use_count: " << sp.use_count() << std::endl; // 输出 1
}
转换为 shared_ptr
#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sp = std::make_shared<int>(20);
    std::weak_ptr<int> wp = sp;

    if (auto sp2 = wp.lock()) { // 尝试获取 shared_ptr
        std::cout << "Value: " << *sp2 << std::endl; // 输出 20
    } else {
        std::cout << "The object has been deleted." << std::endl;
    }
}

详细示例:缓存和观察者模式 
#include <iostream>
#include <memory>
#include <vector>

class Observer {
public:
    virtual void update() = 0;
};

class Subject {
public:
    void addObserver(std::weak_ptr<Observer> observer) {
        observers.push_back(observer);
    }

    void notify() {
        for (auto it = observers.begin(); it != observers.end(); ) {
            if (auto observer = it->lock()) {
                observer->update(); // 调用观察者的 update 方法
                ++it;
            } else {
                it = observers.erase(it); // 移除过期的观察者
            }
        }
    }

private:
    std::vector<std::weak_ptr<Observer>> observers;
};

class ConcreteObserver : public Observer {
public:
    void update() override {
        std::cout << "ConcreteObserver updated!" << std::endl;
    }
};

int main() {
    std::shared_ptr<Subject> subject = std::make_shared<Subject>();

    {
        std::shared_ptr<ConcreteObserver> observer1 = std::make_shared<ConcreteObserver>();
        subject->addObserver(observer1);

        subject->notify(); // 触发通知

        observer1.reset(); // 销毁 observer1
        subject->notify(); // 不再有有效的观察者
    }

    subject->notify(); // 此时 observers 列表应该为空
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值