【C\C++】C++11 智能指针所有使用场景及实例代码

线程间应用

  1. 使用 std::unique_ptr 管理动态分配的对象,并在多个线程中共享:
class MyObject {
public:
    void doSomething() {
        // ...
    }
};

void threadFunc(std::unique_ptr obj) {
    obj->doSomething();
}

int main() {
    std::unique_ptr obj(new MyObject());
    std::thread t1(threadFunc, std::move(obj));
    std::thread t2(threadFunc, std::move(obj));
    t1.join();
    t2.join();
    // obj会在离开作用域时自动释放内存
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::unique_ptr 管理其生命周期。然后,两个线程分别使用 std::movestd::unique_ptr 转移给线程函数 threadFunc,并在函数中使用对象。由于 std::unique_ptr 是独占所有权的智能指针,因此在转移后,原始的 std::unique_ptr 将不再拥有对象的所有权(这里是直接夺权了吗?如何证明 t2 夺取了 t1 的独占式智能指针的使用权),避免了多个线程同时访问同一个对象的问题。(那如果后续t1又要使用,会夺取回去吗?)

  1. 使用 std::shared_ptr 管理动态分配的对象,并在多个线程中共享:
class MyObject {
public:
    void doSomething() {
        // ...
    }
};

void threadFunc(std::shared_ptr obj) {
    obj->doSomething();
}

int main() {
    std::shared_ptr obj(new MyObject());
    std::thread t1(threadFunc, obj);
    std::thread t2(threadFunc, obj);
    t1.join();
    t2.join();
    // obj会在离开作用域时自动释放内存
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::shared_ptr 管理其生命周期。然后,两个线程分别使用 std::shared_ptr 共享对象,并在函数中使用对象。由于 std::shared_ptr 是共享所有权的智能指针,因此多个线程可以同时访问同一个对象,由智能指针来管理对象的生命周期,避免了多个线程同时访问或释放同一个对象的问题。(如何使用 gdb 确认当前智能共享指针引用计数)

这些例子展示了智能指针的更复杂的用法,包括在多线程编程中共享资源、使用独占所有权和共享所有权的智能指针等。智能指针是一种非常有用的C++语言特性,可以提高程序的健壮性和可维护性。

类内应用

以下是更复杂的例子,展示了智能指针的使用场景:

  1. 使用 std::unique_ptr 管理动态分配的对象,并在类中使用:
class MyClass {
public:
    MyClass(std::unique_ptr obj) : m_obj(std::move(obj)) {}
private:
    std::unique_ptr m_obj;
};

int main() {
    std::unique_ptr obj(new MyObject());
    MyClass myClass(std::move(obj));
    // obj会在离开作用域时自动释放内存
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::unique_ptr 管理其生命周期。然后,std::unique_ptr 被转移给类 MyClass 的成员变量 m_obj,由智能指针来管理对象的生命周期,避免了手动释放内存的问题。

  1. 使用 std::shared_ptr 管理动态分配的对象,并在类中使用:
class MyClass {
public:
    MyClass(std::shared_ptr obj) : m_obj(obj) {}
private:
    std::shared_ptr m_obj;
};

int main() {
    std::shared_ptr obj(new MyObject());
    MyClass myClass(obj);
    // obj会在离开作用域时自动释放内存
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::shared_ptr 管理其生命周期。然后,std::shared_ptr 被传递给类 MyClass 的成员变量 m_obj,由智能指针来管理对象的生命周期,避免了手动释放内存的问题。

  1. 使用 std::unique_ptr 管理动态分配的对象,并在容器中存储:
std::vector> vec;
vec.push_back(std::unique_ptr(new MyObject()));
// vec会在离开作用域时自动释放内存

在这个例子中,MyObject 对象被动态分配,并使用 std::unique_ptr 管理其生命周期。然后,std::unique_ptr 被转移给容器 std::vector,由智能指针来管理对象的生命周期,避免了手动释放内存的问题。

  1. 使用 std::shared_ptr 管理动态分配的对象,并在容器中存储:
std::vector> vec;
vec.push_back(std::shared_ptr(new MyObject()));
// vec会在离开作用域时自动释放内存

在这个例子中,MyObject 对象被动态分配,并使用 std::shared_ptr 管理其生命周期。然后,std::shared_ptr 被传递给容器 std::vector,由智能指针来管理对象的生命周期,避免了手动释放内存的问题。

这些例子展示了智能指针的更复杂的用法,包括在类中使用、在容器中存储等。

异常场景应用

以下是更复杂的例子,展示了智能指针的使用场景:

  1. 使用 std::unique_ptr 管理动态分配的对象,并在异常发生时自动释放内存:
void foo() {
    std::unique_ptr obj(new MyObject());
    // do some operations on obj
    if (someCondition) {
        throw std::runtime_error("something went wrong");
    }
    // obj会在离开作用域时自动释放内存
}

int main() {
    try {
        foo();
    } catch (const std::exception& e) {
        // handle exception
    }
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::unique_ptr 管理其生命周期。然后,在函数 foo 中进行一些操作,如果发生异常,则会在函数退出时自动释放内存,避免了内存泄漏的问题。

  1. 使用 std::shared_ptr 管理动态分配的对象,并在异常发生时自动释放内存:
void foo() {
    std::shared_ptr obj(new MyObject());
    // do some operations on obj
    if (someCondition) {
        throw std::runtime_error("something went wrong");
    }
    // obj会在离开作用域时自动释放内存
}

int main() {
    try {
        foo();
    } catch (const std::exception& e) {
        // handle exception
    }
    return 0;
}

在这个例子中,MyObject 对象被动态分配,并使用 std::shared_ptr 管理其生命周期。然后,在函数 foo 中进行一些操作,如果发生异常,则会在函数退出时自动释放内存,避免了内存泄漏的问题。

  1. 使用 std::weak_ptr 避免循环引用:
class B;

class A {
public:
    void setB(std::shared_ptr b) {
        m_b = b;
    }
private:
    std::weak_ptr m_b;
};

class B {
public:
    void setA(std::shared_ptr a) {
        m_a = a;
    }
private:
    std::weak_ptr m_a;
};

int main() {
    std::shared_ptr a(new A());
    std::shared_ptr b(new B());
    a->setB(b);
    b->setA(a);
    // a和b会在离开作用域时自动释放内存,避免循环引用导致的内存泄漏
    return 0;
}

在这个例子中,类 AB 互相引用,如果使用 std::shared_ptr 相互持有,会导致循环引用,从而导致内存泄漏。为了避免这个问题,可以使用 std::weak_ptr 来解决循环引用的问题,避免内存泄漏。

这些例子展示了智能指针的更复杂的用法,包括异常安全、避免循环引用等。

结合 Lambda 表达式的应用

  1. 使用 std::unique_ptr 管理动态分配的对象,并在lambda表达式中使用:
std::unique_ptr obj(new MyObject());
auto lambda = [ptr = std::move(obj)]() {
    // do some operations on ptr
};
// obj会在离开作用域时自动释放内存

在这个例子中,MyObject 对象被动态分配,并使用 std::unique_ptr 管理其生命周期。然后,使用 std::movestd::unique_ptr 转移给lambda表达式,并在表达式中使用对象。由于 std::unique_ptr 是独占所有权的智能指针,因此在转移后,原始的 std::unique_ptr 将不再拥有对象的所有权,避免了手动释放内存的问题。

  1. 使用 std::shared_ptr 管理动态分配的对象,并在lambda表达式中使用:
std::shared_ptr obj(new MyObject());
auto lambda = [ptr = obj]() {
    // do some operations on ptr
};
// obj会在离开作用域时自动释放内存

在这个例子中,MyObject 对象被动态分配,并使用 std::shared_ptr 管理其生命周期。然后,使用 std::shared_ptr 传递给lambda表达式,并在表达式中使用对象。由于 std::shared_ptr 是共享所有权的智能指针,因此多个lambda表达式可以同时访问同一个对象,由智能指针来管理对象的生命周期,避免了多个lambda表达式同时访问或释放同一个对象的问题。

你可能感兴趣的:(C++11,c++,c语言,开发语言)