面试题答案
一键面试-
std::shared_ptr引用计数操作的线程安全性:
std::shared_ptr
的引用计数操作是线程安全的。这意味着多个线程可以同时对std::shared_ptr
进行构造、析构以及赋值操作,而不会导致数据竞争问题。当一个std::shared_ptr
对象被创建、复制、移动或销毁时,其内部的引用计数会被原子地更新。例如:
#include <iostream> #include <memory> #include <thread> std::shared_ptr<int> ptr; void threadFunction() { std::shared_ptr<int> localPtr = ptr; std::cout << "In thread, reference count: " << localPtr.use_count() << std::endl; } int main() { ptr = std::make_shared<int>(42); std::thread t1(threadFunction); std::thread t2(threadFunction); t1.join(); t2.join(); return 0; }
- 在上述代码中,多个线程可以安全地操作
ptr
的引用计数。
-
确保
std::shared_ptr
在多线程中的正确使用:- 虽然引用计数操作是线程安全的,但如果涉及到对
std::shared_ptr
所指向对象的读写操作,仍然需要额外的同步机制。例如,可以使用std::mutex
来保护对指向对象的访问:
#include <iostream> #include <memory> #include <thread> #include <mutex> std::shared_ptr<int> ptr; std::mutex mtx; void threadFunction() { std::unique_lock<std::mutex> lock(mtx); std::shared_ptr<int> localPtr = ptr; lock.unlock(); if (localPtr) { std::cout << "In thread, value: " << *localPtr << std::endl; } } int main() { ptr = std::make_shared<int>(42); std::thread t1(threadFunction); std::thread t2(threadFunction); t1.join(); t2.join(); return 0; }
- 在这个例子中,
std::mutex
用于保护对ptr
的访问,避免在读取ptr
所指向对象时发生数据竞争。
- 虽然引用计数操作是线程安全的,但如果涉及到对
-
为
std::shared_ptr
定义并使用自定义删除器:- 定义自定义删除器的语法:
- 可以通过在构造
std::shared_ptr
时传入一个可调用对象(函数指针、lambda表达式或仿函数)来定义自定义删除器。例如,使用函数指针作为自定义删除器:
#include <iostream> #include <memory> void customDeleter(int* ptr) { std::cout << "Custom deleter called" << std::endl; delete ptr; } int main() { std::shared_ptr<int> ptr(new int(42), customDeleter); return 0; }
- 使用lambda表达式作为自定义删除器:
#include <iostream> #include <memory> int main() { std::shared_ptr<int> ptr(new int(42), [](int* p) { std::cout << "Custom deleter called" << std::endl; delete p; }); return 0; }
- 可以通过在构造
- 使用自定义删除器的实际意义:
- 资源管理灵活性:可以实现非标准的资源释放逻辑。例如,对于动态分配的数组,可以使用
delete[]
而不是delete
来释放内存。对于一些需要特殊清理操作的资源,如文件句柄(除了关闭文件,可能还需要做一些日志记录等操作),可以在自定义删除器中实现这些额外的清理逻辑。 - 适配不同的资源管理策略:在一些情况下,可能需要使用第三方库提供的资源释放函数,自定义删除器可以方便地适配这种情况,使
std::shared_ptr
能够正确管理这些资源。
- 资源管理灵活性:可以实现非标准的资源释放逻辑。例如,对于动态分配的数组,可以使用
- 定义自定义删除器的语法: