Catalog
Algorithm
C++
Common
Docker
Javascript
Network
Node
唯一指针(unique_ptr),顾名思义就是该指针是唯一的,不能分享(赋值)给其他指针,也不能讲其指赋予给其他唯一指针变量。唯一指针只能被移动,意思是它只能从一个unique_ptr移动到另一个unique_ptr,一旦指针被移动到另一个唯一指针中,前一个的唯一指针就失去这个指针源,不再会指向对应的值。std::move来移动唯一指针
唯一指针的方法在memory标准库中,使用时需要引入此lib
#include <iostream>
#include <memory>
class Test {
private:
int i, j, k;
public:
Test(int a, int b, int c): i(a), j(b), k(c) {}
int sum() {
return i + j + k;
}
}
int main() {
std::unique_ptr<Test> ptr1 = std::make_unique<Test>(1, 2, 3);
std::cout << ptr1->sum() << std::endl; // 6
std::unique_ptr<Test> ptr2 = std::move(ptr1);
std::cout << ptr2->sum() << std::endl; // 6
return 0;
}
根据唯一指针的特性,可以自己手动实现其类和方法
#include <iostream>
template<typename T>
class MyUniquePtr {
private:
T *ptr;
public:
explicit MyUniquePtr(T *p = nullptr): ptr(p) {}
~MyUniquePtr() { delete ptr; }
// 禁止拷贝
MyUniquePtr(const MyUniquePtr &) = delete;
MyUniquePtr &operator=(const MyUniquePtr &) = delete;
// 支持移动
MyUniquePtr(MyUniquePtr &&other) noexcept {
ptr = other.ptr;
other.ptr = nullptr;
}
MyUniquePtr &operator=(MyUniquePtr &&other) noexcept {
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
T *operator->() { return ptr; }
T &opeartor*() { return *ptr; }
};
template<typename T, typename ...Args>
MyUniquePtr<T> my_make_unique(Args && ...args) {
return MyUniquePtr<T>(new T(std::forward<Args>(args)...));
}
class Test {
private:
int i, j, k;
public:
Test(int a, int b, int c): i(a), j(b), k(c) {}
int sum() {
return i + j + k;
}
};
int main() {
MyUniquePtr<Test> ptr1 = my_make_unique<Test>(1, 2, 3);
std::cout << ptr1->sum() << std::endl;
MyUniquePtr<Test> ptr2 = std::move(ptr1);
std::cout << ptr2->sum() << std::endl;
return 0;
}

#include <iostream>
#include <memory>
int main() {
std::shared_ptr<int> s1 = std::shared_ptr<int>(new int(10));
std::shared_ptr<int> s2 = s1;
std::cout << *s1 << std::endl; // 10
std::cout << *s2 << std::endl; // 10
}
#include <iostream>
template <typename T> class MySharedPtr {
private:
T *ptr;
int *ref_counter;
public:
MySharedPtr(T *p) : ptr(p) {
if (p) {
ref_counter = new int(1);
} else {
ref_counter = nullptr;
}
}
// 拷贝构造
MySharedPtr(const MySharedPtr &other) {
ptr = other.ptr;
ref_counter = other.ref_counter;
(*ref_counter)++;
}
// 拷贝赋值
MySharedPtr &operator=(const MySharedPtr &other) {
if (this != &other) {
release();
ptr = other.ptr;
ref_counter = other.ref_counter;
(*ref_counter)++;
}
return *this;
}
~MySharedPtr() { release(); }
void release() {
if (ref_counter) {
(*ref_counter)--;
if (*ref_counter == 0) {
delete ptr;
delete ref_counter;
}
}
}
T *operator->() { return ptr; }
T &operator*() { return *ptr; }
int use_count() const { return ref_counter ? *ref_counter : 0; }
};
class Test {
private:
int i, j, k;
public:
Test(int a, int b, int c) : i(a), j(b), k(c) {}
int sum() { return i + j + k; }
};
int main() {
MySharedPtr<Test> ptr1 = MySharedPtr<Test>(new Test(1, 2, 3));
{
MySharedPtr<Test> ptr2 = ptr1;
std::cout << ptr1.use_count() << std::endl; // 2
}
std::cout << ptr1.use_count() << std::endl; // 1
return 0;
}
弱引用是不会增加对象生命周期管理计数的引用,目的是避免指针的共享所有权
struct A;
struct B;
struct A {
std::shared_ptr<B> b;
}
struct B {
std::shared_ptr<A> a;
}
// 引用计数永远不为0, 会造成内存泄漏
弱引用特性
弱引用使用
int main() {
std::shared_ptr<int> sp = std::make_shared<int>(10);
std::weak_ptr<int> wp = sp;
if (!wp.expired()) {
std::cout << "Object still alive" << std::cout;
}
if (auto sp2 = wp.lock()) {
std::cout << *sp2 << std::endl;
} else {
std::cout << "Object is already released." << std::endl;
}
}
手写若引用需要实现三部分:
shared_count和weak_count 两个变量,当shared_count == 0 时, 对象销毁; 当shared_count 和 weak_count 都为0时,控制块销毁其中 WeakPtr 需要实现:
#include <iostream>
struct ControlBlock {
int shared_count;
int weak_count;
};
// 实现简易Share_Ptr
template <typename T> class MySharedPtr {
public:
ControlBlock *cb;
T *ptr;
MySharedPtr(T *ptr) : ptr(ptr) {
if (ptr) {
cb = new ControlBlock{1, 0};
} else {
cb = nullptr;
}
}
MySharedPtr(T *p, ControlBlock *c) {
ptr = p;
cb = c;
}
// 拷贝构造
MySharedPtr(MySharedPtr &other) {
ptr = other.ptr;
cb = other.cb;
if (cb) {
cb->shared_count++;
}
}
// 拷贝赋值
MySharedPtr &operator=(const MySharedPtr &other) {
if (this != &other) {
release();
ptr = other.ptr;
cb->shared_count = other.cb->shared_count;
(cb->shared_count)++;
}
return *this;
}
~MySharedPtr() { release(); }
void release() {
if (!cb)
return;
cb->shared_count--;
if (cb->shared_count == 0) {
delete ptr;
if (cb->weak_count == 0) {
delete cb;
}
}
}
T *operator->() { return ptr; }
T &operator*() { return *ptr; }
};
template <typename T> class WeakPtr {
public:
T *ptr;
ControlBlock *cb;
WeakPtr() : ptr(nullptr), cb(nullptr) {}
// 从 SharedPtr 构造
WeakPtr(const MySharedPtr<T> &sp) {
ptr = sp.ptr;
cb = sp.cb;
if (cb)
cb->weak_count++;
}
// 拷贝构造
WeakPtr(const WeakPtr &other) {
ptr = other.ptr;
cb = other.cb;
if (cb)
cb->weak_count++;
}
~WeakPtr() {
if (!cb)
return;
cb->weak_count--;
if (cb->weak_count == 0 && cb->shared_count == 0) {
delete cb;
}
}
bool expired() const { return !cb || cb->shared_count == 0; }
MySharedPtr<T> lock() const {
if (expired()) {
return MySharedPtr<T>();
}
cb->shared_count++;
return MySharedPtr<T>(ptr, cb);
}
};
int main() {
MySharedPtr<int> mp1 = MySharedPtr<int>(new int(10)); // share_count = 1 weak_count = 0;
MySharedPtr<int> mp2 = mp1; // share_count = 2 weak_count = 0;
WeakPtr<int> wp1 = mp1; // share_count = 2 weak_count = 1;
{
WeakPtr<int> wp2 = wp1; // share_count = 2 weak_count = 2;
} // share_count = 2 weak_count = 1;
auto p3 = wp1.lock(); // share_count = 3 weak_count = 1;
p3.~MySharedPtr(); // share_count = 2 weak_count = 1;
p2.~MySharedPtr(); // share_count = 1 weak_count = 1;
p1.~MySharedPtr(); // share_count = 0 weak_count = 1; Delete object
wp1.~WeakPtr(); // share_count = 0 weak_count = 0; Delete control block
}
#include <condition_variable>
#include <functional>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include <utility>
#include <vector>
class ThreadPool {
private:
std::vector<std::thread> pool;
std::queue<std::function<void()>> queue;
bool stop = false;
std::mutex mtx;
std::condition_variable cv;
private:
// 每个线程的执行方法
void worker_loop() {
std::function<void()> task;
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Thread id: " << std::this_thread::get_id() << " is running"
<< std::endl;
}
while (true) {
// 插入数据时添加唯一锁
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [this] { return stop || !queue.empty(); });
if (stop && queue.empty()) {
return;
}
// 取队首任务
task = std::move(queue.front());
// 弹出队首任务
queue.pop();
}
try {
task();
} catch (std::exception &e) {
std::cout << "Thread execute error: " << e.what() << std::endl;
}
}
}
public:
// 构造线程池
ThreadPool(int thread_num) {
for (int i = 0; i < thread_num; i++) {
pool.emplace_back(&ThreadPool::worker_loop, this);
}
}
// 析构函数
~ThreadPool() {
{
std::lock_guard<std::mutex> lock(mtx);
stop = true;
}
// 通知所有线程往下执行
cv.notify_all();
for (auto &worker : pool) {
if (worker.joinable()) {
worker.join();
}
}
}
// 向线程池队列提交任务
template <typename F, typename... Args>
void submit(F &&func, Args &&...args) {
std::lock_guard<std::mutex> lock(mtx);
auto task = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
if (stop) {
return;
}
queue.emplace(std::move(task));
cv.notify_one();
}
};
std::mutex cout_mtx;
// 创建测试任务
void delayedTask(int id, int delay_ms) {
{
std::lock_guard<std::mutex> lock(cout_mtx);
std::cout << "[Task " << id << "] start on thread "
<< std::this_thread::get_id() << ", delay = " << delay_ms
<< "ms\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
{
std::lock_guard<std::mutex> lock(cout_mtx);
std::cout << "[Task " << id << "] end on thread "
<< std::this_thread::get_id() << "\n";
}
}
int main() {
ThreadPool pool(5);
pool.submit(delayedTask, 1, 1000);
pool.submit(delayedTask, 2, 2000);
pool.submit(delayedTask, 3, 3000);
pool.submit(delayedTask, 4, 4000);
pool.submit(delayedTask, 5, 5000);
pool.submit(delayedTask, 6, 6000);
return 0;
/**
* Possible output
* Thread id: 136194589456064 is running
Thread id: 136194486695616 is running
[Task 1] start on thread Thread id: 136194589456064, delay = 1000ms
136194564277952 is running
[Task 2] start on thread 136194564277952, delay = 2000ms
Thread id: 136194581063360 is running
[Task 3] start on thread 136194581063360, delay = 3000ms
Thread id: [Task 136194572670656 is running
4] start on thread 136194486695616, delay = 4000ms
[Task 5] start on thread 136194572670656, delay = 5000ms
[Task 1] end on thread 136194589456064
[Task 6] start on thread 136194589456064, delay = 6000ms
[Task 2] end on thread 136194564277952
[Task 3] end on thread 136194581063360
[Task 4] end on thread 136194486695616
[Task 5] end on thread 136194572670656
[Task 6] end on thread 136194589456064
*/
}