C++11 智能指针的Cast

本文详细介绍了C++11及以后版本中智能指针的转换方法,包括static_pointer_cast, dynamic_pointer_cast, const_pointer_cast和reinterpret_pointer_cast的使用,对比了C++11之前的转换方式,展示了如何在继承层次结构中进行指针转换,并提供了具体示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 C++11前

在C++11之前,对智能指针转换的方法大概如下:

std::shared_ptr<T>(static_cast<T*>(r.get())) 
std::shared_ptr<T>(dynamic_cast<T*>(r.get())) 
std::shared_ptr<T>(const_cast<T*>(r.get())) 

但它们有可能导致未定义行为,即删除同一对象两次。

二 C++11

C++11开始引入了std::static_pointer_cast,std::dynamic_pointer_cast,std::const_pointer_cast。(std::reinterpret_pointer_cast在C++17中引入)。头文件为<memory>,申明如下:

template< class T, class U > 
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (1)(C++11 起)
template< class T, class U > 
std::shared_ptr<T> static_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (2)(C++20 起)
template< class T, class U > 
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (3)(C++11 起)
template< class T, class U > 
std::shared_ptr<T> dynamic_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (4)(C++20 起)
template< class T, class U > 
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (5)(C++11 起)
template< class T, class U > 
std::shared_ptr<T> const_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (6)(C++20 起)
template< class T, class U > 
std::shared_ptr<T> reinterpret_pointer_cast( const std::shared_ptr<U>& r ) noexcept; (7)(C++17 起)
template< class T, class U > 
std::shared_ptr<T> reinterpret_pointer_cast( std::shared_ptr<U>&& r ) noexcept; (8)(C++20 起)

特别是C++20中引入的右值引入版本,除了(4)若dynamic_cast失败不会更改r,(2)(6)(8)调用后,r为空且r.get() == nullptr 

三 举例

#include <iostream>
#include <memory>
 
struct Base 
{ 
    int a; 
    virtual void f() const { std::cout << "I am base!\n";}
    virtual ~Base(){}
};
 
struct Derived : Base
{
    void f() const override
    { std::cout << "I am derived!\n"; }
    ~Derived(){}
};
 
int main(){
    auto basePtr = std::make_shared<Base>();
    std::cout << "Base pointer says: ";
    basePtr->f();
 
    auto derivedPtr = std::make_shared<Derived>();
    std::cout << "Derived pointer says: ";
    derivedPtr->f();
 
    // static_pointer_cast to go up class hierarchy
    basePtr = std::static_pointer_cast<Base>(derivedPtr);
    std::cout << "Base pointer to derived says: ";
    basePtr->f();
 
    // dynamic_pointer_cast to go down/across class hierarchy
    auto downcastedPtr = std::dynamic_pointer_cast<Derived>(basePtr);
    if(downcastedPtr)
    { 
        std::cout << "Downcasted pointer says: ";
        downcastedPtr->f(); 
    }
 
    // All pointers to derived share ownership
    std::cout << "Pointers to underlying derived: " 
            << derivedPtr.use_count() 
            << "\n"; 
}

 结果:

四 参考

cppreference

### C++11 智能指针实现详解 #### 1. `unique_ptr` 的实现 `unique_ptr` 是一种独占式智能指针,其核心特性在于它的不可复制性和资源的唯一所有权。其实现主要依赖于模板类以及删除拷贝构造函数和赋值运算符来确保独占性。 以下是简化版的 `unique_ptr` 实现: ```cpp template<typename T> class unique_ptr { public: // 构造函数 explicit unique_ptr(T* ptr = nullptr) noexcept : _ptr(ptr) {} // 删除拷贝构造函数和赋值运算符 unique_ptr(const unique_ptr& other) = delete; unique_ptr& operator=(const unique_ptr& other) = delete; // 移动语义 unique_ptr(unique_ptr&& other) noexcept : _ptr(other._ptr) { other._ptr = nullptr; } unique_ptr& operator=(unique_ptr&& other) noexcept { if (this != &other) { reset(other.release()); } return *this; } // 获取底层指针 T* get() const noexcept { return _ptr; } // 显式释放资源 void reset(T* ptr = nullptr) noexcept { if (_ptr && _ptr != ptr) { delete _ptr; } _ptr = ptr; } // 转让所有权 T* release() noexcept { T* temp = _ptr; _ptr = nullptr; return temp; } // 解引用操作 T& operator*() const noexcept { return *_ptr; } T* operator->() const noexcept { return _ptr; } // 判断是否为空 explicit operator bool() const noexcept { return _ptr != nullptr; } ~unique_ptr() noexcept { if (_ptr) { delete _ptr; } } private: T* _ptr = nullptr; }; ``` 此实现通过移动语义实现了资源转移的功能,并且禁用了拷贝构造函数和赋值运算符以防止共享所有权的情况发生[^3]。 --- #### 2. `shared_ptr` 的实现 `shared_ptr` 使用引用计数机制来管理动态分配的对象。当最后一个 `shared_ptr` 对象销毁时,才会释放其所管理的资源。为了提高性能并减少循环引用的风险,通常会引入控制块的概念。 以下是简化版的 `shared_ptr` 实现: ```cpp #include <memory> template<typename T> class shared_ptr { public: // 构造函数 explicit shared_ptr(T* ptr = nullptr) : _ptr(ptr), _count(new std::size_t(1)) {} // 复制构造函数 shared_ptr(const shared_ptr& other) : _ptr(other._ptr), _count(other._count) { ++(*_count); } // 赋值运算符 shared_ptr& operator=(const shared_ptr& other) { if (this != &other) { --(*_count); if (*_count == 0) { delete _ptr; delete _count; } _ptr = other._ptr; _count = other._count; ++(*_count); } return *this; } // 销毁函数 ~shared_ptr() { --(*_count); if (*_count == 0) { delete _ptr; delete _count; } } // 获取底层指针 T* get() const noexcept { return _ptr; } // 解引用操作 T& operator*() const noexcept { return *_ptr; } T* operator->() const noexcept { return _ptr; } // 返回引用计数值 long use_count() const noexcept { return static_cast<long>(*_count); } private: T* _ptr = nullptr; std::size_t* _count = nullptr; }; ``` 在此实现中,`std::size_t* _count` 表示引用计数器,用于跟踪有多少个 `shared_ptr` 正在共同拥有该资源。每当创建一个新的副本时,引用计数加一;而当一个实例被销毁时,引用计数减一。如果引用计数降为零,则表示没有任何 `shared_ptr` 存活,此时将释放资源[^1]。 --- #### 3. `weak_ptr` 的实现 `weak_ptr` 不增加引用计数,因此不会阻止所指向对象的销毁。它可以用来观察由 `shared_ptr` 管理的对象是否存在。只有当对应的 `shared_ptr` 尚未销毁时,才能通过 `lock()` 方法获得有效的 `shared_ptr`。 以下是简化版的 `weak_ptr` 实现: ```cpp template<typename T> class weak_ptr { public: // 构造函数 weak_ptr() : _sp(nullptr) {} weak_ptr(std::shared_ptr<T> sp) : _sp(sp) {} // lock 函数尝试返回一个 shared_ptr std::shared_ptr<T> lock() const { if (!_sp || !_sp.use_count()) { return std::shared_ptr<T>(); } return std::shared_ptr<T>(_sp); } // 是否过期 bool expired() const noexcept { return !(_sp && _sp.use_count()); } private: std::shared_ptr<T> _sp; }; ``` 在这个实现中,`weak_ptr` 并不直接持有原始指针,而是保存了一个对 `shared_ptr` 的弱引用。调用 `lock()` 可以检查目标对象是否仍然存在,并返回一个临时的 `shared_ptr` 来访问它[^1]。 --- ### 总结 - **`unique_ptr`** 提供了一种轻量级、高效的解决方案,适用于不需要共享所有权的场景。 - **`shared_ptr`** 基于引用计数技术,适合需要多个指针共享同一个对象的情形。 - **`weak_ptr`** 主要作为辅助工具配合 `shared_ptr` 使用,避免因循环引用而导致内存泄漏的问题。 这些智能指针的设计极大地提高了现代 C++ 中动态内存管理的安全性和便利性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值