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

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

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

线程间应用

  1. 使用 std::unique_ptr 管理动态分配的对象,并在多个线程中共享:
class MyObject {
public:void doSomething() {// ...}
};void threadFunc(std::unique_ptr<MyObject> obj) {obj->doSomething();
}int main() {std::unique_ptr<MyObject> 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<MyObject> obj) {obj->doSomething();
}int main() {std::shared_ptr<MyObject> 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<MyObject> obj) : m_obj(std::move(obj)) {}
private:std::unique_ptr<MyObject> m_obj;
};int main() {std::unique_ptr<MyObject> 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<MyObject> obj) : m_obj(obj) {}
private:std::shared_ptr<MyObject> m_obj;
};int main() {std::shared_ptr<MyObject> 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<std::unique_ptr<MyObject>> vec;
vec.push_back(std::unique_ptr<MyObject>(new MyObject()));
// vec会在离开作用域时自动释放内存

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

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

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

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

异常场景应用

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

  1. 使用 std::unique_ptr 管理动态分配的对象,并在异常发生时自动释放内存:
void foo() {std::unique_ptr<MyObject> obj(new MyObject());// do some operations on objif (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<MyObject> obj(new MyObject());// do some operations on objif (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> b) {m_b = b;}
private:std::weak_ptr<B> m_b;
};class B {
public:void setA(std::shared_ptr<A> a) {m_a = a;}
private:std::weak_ptr<A> m_a;
};int main() {std::shared_ptr<A> a(new A());std::shared_ptr<B> 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<MyObject> 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<MyObject> 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表达式同时访问或释放同一个对象的问题。