Last active
September 11, 2025 08:01
-
-
Save vacing/c098fbbbd5f9151ff1ee73748ff96edc to your computer and use it in GitHub Desktop.
shared_pointer wrapper for nonprimitive c struct .
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <memory> | |
| #include <iostream> | |
| #include <cstdio> | |
| /** | |
| * @file safe_ptr.h | |
| * @author vacingfang | |
| * @version 0.1, 2025-08-14, init version | |
| * @version 0.11, 2025-08-20, more comments | |
| * @brief | |
| * This is a shared_ptr wrapper for c-style non-primitive struct. These type | |
| * have their own release function to relese the resources they hold, such as | |
| * memory, file descriptor and so on. | |
| * Deleter class must process nullptr, such as | |
| * ```c++ | |
| * struct TestDeleter { | |
| * void operator()(std::nullptr_t) {} // for nullptr | |
| * ... | |
| * }; | |
| * ``` | |
| * Usage of SafeSPtr | |
| * ``` | |
| * usging TestSPtr = SafeSptr<Test, TestDeleter>; | |
| * TestSPtr tsptr{new Test}; | |
| * // TestSPtr tsptr = new Test(); // not support, only explicit construct | |
| * ``` | |
| */ | |
| template<typename T, typename Deleter> | |
| struct SafeSPtr : public std::shared_ptr<T> { | |
| // default, Deleter must process nullptr !! | |
| SafeSPtr() : std::shared_ptr<T>(nullptr, Deleter()) {} | |
| // default deleter, will destroy unique_ptr assign | |
| // SafePtr() : std::shared_ptr<T>() {} // wrong !! | |
| // big five | |
| SafeSPtr(const SafeSPtr&) = default; | |
| SafeSPtr(SafeSPtr&&) noexcept = default; | |
| SafeSPtr& operator=(const SafeSPtr&) = default; | |
| SafeSPtr& operator=(SafeSPtr&&) noexcept = default; | |
| virtual ~SafeSPtr() = default; | |
| // Explicit constructor: prevents implicit conversion from raw pointer | |
| // which could otherwise cause unintended ownership transfer and unexpected deletion. | |
| // keep align with std::shared_ptr<T> | |
| explicit SafeSPtr(T* p) : std::shared_ptr<T>(p, Deleter()) {} | |
| // unique pointer | |
| SafeSPtr(std::unique_ptr<T>&& up) : SafeSPtr(up.release()) {} | |
| SafeSPtr(std::unique_ptr<T, Deleter>&& up) : SafeSPtr(up.release()) {} | |
| SafeSPtr& operator=(std::unique_ptr<T>&& up) { | |
| this->reset(up.release()); | |
| return *this; | |
| } | |
| SafeSPtr& operator=(std::unique_ptr<T, Deleter>&& up) { | |
| this->reset(up.release()); | |
| return *this; | |
| } | |
| // no shared_ptr style use | |
| template<typename D> SafeSPtr(T*, D) = delete; | |
| // no common shared_ptr<T> | |
| SafeSPtr(std::shared_ptr<T>&& sp) = delete; | |
| SafeSPtr(const std::shared_ptr<T>&) = delete; | |
| }; | |
| /** | |
| * @brief build command | |
| * g++ safe_ptr.cpp -std=c++14 -o safe_ptr -g && ./safe_ptr | |
| */ | |
| static int struct_ind = 0; | |
| struct Cstruct { | |
| int *pi; | |
| int ind; | |
| Cstruct() { | |
| ind = ++struct_ind; | |
| printf("init [%d] %p\n", ind, this); | |
| this->pi = (int *)malloc(10); | |
| } | |
| }; | |
| void destroy(Cstruct* p, int type) { | |
| printf("destroy [T%d][%d] %p\n", type, (p? p->ind : -1), p); | |
| if (p && p->pi) free(p->pi); | |
| } | |
| struct CDeleter { | |
| void operator()(std::nullptr_t) {} // for nullptr | |
| void operator()(Cstruct *p) { | |
| destroy(p, 1); | |
| } | |
| void operator()(int *p) { | |
| } | |
| }; | |
| struct CDeleter2 { | |
| void operator()(std::nullptr_t&) {} // for nullptr | |
| void operator()(Cstruct *p) { | |
| destroy(p, 2); | |
| } | |
| void operator()(int *p) { | |
| } | |
| }; | |
| using CstructSPtr = SafeSPtr<Cstruct, CDeleter>; | |
| using CstructSPtr2 = SafeSPtr<Cstruct, CDeleter2>; | |
| using CstructPtr = std::unique_ptr<Cstruct, CDeleter>; | |
| int main() { | |
| CstructSPtr pnull; | |
| CstructSPtr p1(new Cstruct); | |
| CstructSPtr p2(new Cstruct); | |
| printf("p2 = p1\n"); | |
| p2 = p1; | |
| std::shared_ptr<Cstruct> sp3; | |
| { | |
| CstructSPtr p3(new Cstruct); | |
| printf("sp3 = p3\n"); | |
| sp3 = p3; | |
| } | |
| CstructSPtr up4 = std::make_unique<Cstruct>(); | |
| CstructSPtr up5 = std::make_unique<Cstruct>(); | |
| printf("pnull = up4\n"); | |
| pnull = up4; | |
| // CstructPtr up5 = std::make_unique<Cstruct>(); // 失败,类型不兼容 | |
| // CstructPtr up5 = std::make_unique<Cstruct, CDeleter>(); // make_unique() 不能指定 deleter | |
| CstructSPtr2 p6(new Cstruct); | |
| // CstructSPtr ptmp = p6; // 退化成普通的 std::shared_ptr<T> 类型构造,已delete | |
| CstructSPtr p7; | |
| // p7 = p6; // 没有CstructSPtr2 和 CstructSPtr 之间赋值函数,p6 会尝试转换成 CstructSPtr 对象后再赋值 | |
| // 转换时退化成普通的 std::shared_ptr<T> 类型构造,已delete | |
| printf("p1.reset()\n"); | |
| p1.reset(); | |
| printf("p2.reset()\n"); | |
| p2.reset(); | |
| // 不支持,防止函数传参 误将raw 指针释放 | |
| // CstructSPtr p8 = new Cstruct(); | |
| // std::shared_ptr<Cstruct> p8 = new Cstruct(); | |
| CstructSPtr pnullptr; | |
| printf("end\n"); | |
| return 0; | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
g++ safe_ptr.cpp -std=c++14 -o safe_ptr -g && ./safe_ptr