Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/memory/shared ptr/pointer cast"

From cppreference.com
< cpp‎ | memory‎ | shared ptr
(Updated the 4 cases after the "Let Y be ..." sentence to use Y instead of T.)
m ({{c}}, @-@ -> @,@)
 
(15 intermediate revisions by 10 users not shown)
Line 1: Line 1:
{{cpp/title | static_pointer_cast | dynamic_pointer_cast | const_pointer_cast | reinterpret_pointer_cast}}
+
{{cpp/title|static_pointer_cast|dynamic_pointer_cast|const_pointer_cast|reinterpret_pointer_cast}}
 
{{cpp/memory/shared_ptr/navbar}}
 
{{cpp/memory/shared_ptr/navbar}}
 
{{dcl begin}}
 
{{dcl begin}}
{{dcl | num=1 | since=c++11 | 1=  
+
{{dcl header|memory}}
template< class T, class U >  
+
{{dcla|num=1|since=c++11|1=
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r );
+
template< class T, class U >
 +
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept;
 
}}
 
}}
{{dcl | num=2 | since=c++11 | 1=  
+
{{dcl|num=2|since=c++20|1=
template< class T, class U >  
+
template< class T, class U >
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r );
+
std::shared_ptr<T> static_pointer_cast( std::shared_ptr<U>&& r ) noexcept;
 
}}
 
}}
{{dcl | num=3 | since=c++11 | 1=  
+
{{dcla|num=3|since=c++11|1=
template< class T, class U >  
+
template< class T, class U >
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r );
+
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept;
 
}}
 
}}
{{dcl | num=4 | since=c++17 | 1=  
+
{{dcl|num=4|since=c++20|1=
template< class T, class U >  
+
template< class T, class U >
std::shared_ptr<T> reinterpret_pointer_cast( const std::shared_ptr<U>& r );
+
std::shared_ptr<T> dynamic_pointer_cast( std::shared_ptr<U>&& r ) noexcept;
 +
}}
 +
{{dcla|num=5|since=c++11|1=
 +
template< class T, class U >
 +
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r ) noexcept;
 +
}}
 +
{{dcl|num=6|since=c++20|1=
 +
template< class T, class U >
 +
std::shared_ptr<T> const_pointer_cast( std::shared_ptr<U>&& r ) noexcept;
 +
}}
 +
{{dcla|num=7|since=c++17|1=
 +
template< class T, class U >
 +
std::shared_ptr<T> reinterpret_pointer_cast( const std::shared_ptr<U>& r ) noexcept;
 +
}}
 +
{{dcl|num=8|since=c++20|1=
 +
template< class T, class U >
 +
std::shared_ptr<T> reinterpret_pointer_cast( std::shared_ptr<U>&& r ) noexcept;
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
Creates a new instance of {{lc|std::shared_ptr}} whose stored pointer is obtained from {{tt|r}}'s stored pointer using a cast expression. If {{tt|r}} is empty, so is the new {{tt|shared_ptr}} (but its stored pointer is not necessarily null).
+
Creates a new instance of {{lc|std::shared_ptr}} whose stored pointer is obtained from {{c|r}}'s stored pointer using a cast expression.
  
Otherwise, the new {{tt|shared_ptr}} will share ownership with {{tt|r}}, except that it is empty if the {{tt|dynamic_cast}} performed by {{tt|dynamic_pointer_cast}} returns a null pointer.
+
If {{c|r}} is empty, so is the new {{tt|shared_ptr}} (but its stored pointer is not necessarily null). Otherwise, the new {{tt|shared_ptr}} will share ownership with the initial value of {{c|r}}, except that it is empty if the {{tt|dynamic_cast}} performed by {{tt|dynamic_pointer_cast}} returns a null pointer.
  
Let {{tt|Y}} be {{c|typename std::shared_ptr<T>::element_type}}, then the resulting {{lc|std::shared_ptr}}'s stored pointer will be obtained by calling (in respective order):
+
Let {{tt|Y}} be {{c|typename std::shared_ptr<T>::element_type}}, then the resulting {{lc|std::shared_ptr}}'s stored pointer will be obtained by evaluating, respectively:
  
@1@ {{c|static_cast<Y*>(r.get())}}.
+
@1,2@ {{c|static_cast<Y*>(r.get())}}
@2@ {{c|dynamic_cast<Y*>(r.get())}} (If the result of the {{tt|dynamic_cast}} is a null pointer value, the returned {{tt|shared_ptr}} will be empty).
+
@3,4@ {{c|dynamic_cast<Y*>(r.get())}}. If the result of the {{tt|dynamic_cast}} is a null pointer value, the returned {{tt|shared_ptr}} will be empty.
@3@ {{c|const_cast<Y*>(r.get())}}.
+
@5,6@ {{c|const_cast<Y*>(r.get())}}
@4@ {{c|reinterpret_cast<Y*>(r.get())}}
+
@7,8@ {{c|reinterpret_cast<Y*>(r.get())}}
  
 
The behavior of these functions is undefined unless the corresponding cast from {{tt|U*}} to {{tt|T*}} is well formed:
 
The behavior of these functions is undefined unless the corresponding cast from {{tt|U*}} to {{tt|T*}} is well formed:
  
@1@ The behavior is undefined unless {{c|static_cast<T*>((U*)nullptr)}} is well formed.
+
@1,2@ The behavior is undefined unless {{c|static_cast<T*>((U*)nullptr)}} is well formed.
@2@ The behavior is undefined unless {{c|dynamic_cast<T*>((U*)nullptr)}} is well formed.
+
@3,4@ The behavior is undefined unless {{c|dynamic_cast<T*>((U*)nullptr)}} is well formed.
@3@ The behavior is undefined unless {{c|const_cast<T*>((U*)nullptr)}} is well formed.
+
@5,6@ The behavior is undefined unless {{c|const_cast<T*>((U*)nullptr)}} is well formed.
@4@ The behavior is undefined unless {{c|reinterpret_cast<T*>((U*)nullptr)}} is well formed.
+
@7,8@ The behavior is undefined unless {{c|reinterpret_cast<T*>((U*)nullptr)}} is well formed.
 +
 
 +
{{rrev|since=c++20|
 +
After calling the rvalue overloads {{v|2,4,6,8}}, {{c|r}} is empty and {{c|r.get() {{==}} nullptr}}, except that {{c|r}} is not modified for {{tt|dynamic_pointer_cast}} {{v|4}} if the {{c|dynamic_cast}} fails.
 +
}}
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | r | The pointer to convert}}
+
{{par|r|the pointer to convert}}
 
{{par end}}
 
{{par end}}
 
===Exceptions===
 
{{noexcept}}
 
  
 
===Notes===
 
===Notes===
Line 49: Line 67:
  
 
===Possible implementation===
 
===Possible implementation===
{{eq fun|1=
+
{{eq impl
template< class T, class U >  
+
|title1=static_pointer_cast|ver1=1|1=
std::shared_ptr<T> static_pointer_cast( const std::shared_ptr<U>& r ) noexcept
+
template<class T, class U>
 +
std::shared_ptr<T> static_pointer_cast(const std::shared_ptr<U>& r) noexcept
 
{
 
{
 
     auto p = static_cast<typename std::shared_ptr<T>::element_type*>(r.get());
 
     auto p = static_cast<typename std::shared_ptr<T>::element_type*>(r.get());
     return std::shared_ptr<T>(r, p);
+
     return std::shared_ptr<T>{r, p};
 
}
 
}
|2=
+
|title2=dynamic_pointer_cast|ver2=3|2=
template< class T, class U >  
+
template<class T, class U>
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept
+
std::shared_ptr<T> dynamic_pointer_cast(const std::shared_ptr<U>& r) noexcept
 
{
 
{
     if (auto p = dynamic_cast<typename std::shared_ptr<T>::element_type*>(r.get())) {
+
     if (auto p = dynamic_cast<typename std::shared_ptr<T>::element_type*>(r.get()))
         return std::shared_ptr<T>(r, p);
+
         return std::shared_ptr<T>{r, p};
     } else {
+
     else
         return std::shared_ptr<T>();
+
         return std::shared_ptr<T>{};
    }
+
 
}
 
}
|3=
+
|title3=const_pointer_cast|ver3=5|3=
template< class T, class U >  
+
template<class T, class U>
std::shared_ptr<T> const_pointer_cast( const std::shared_ptr<U>& r ) noexcept
+
std::shared_ptr<T> const_pointer_cast(const std::shared_ptr<U>& r) noexcept
 
{
 
{
 
     auto p = const_cast<typename std::shared_ptr<T>::element_type*>(r.get());
 
     auto p = const_cast<typename std::shared_ptr<T>::element_type*>(r.get());
     return std::shared_ptr<T>(r, p);
+
     return std::shared_ptr<T>{r, p};
 +
}
 +
|title4=reinterpret_pointer_cast|ver4=7|4=
 +
template<class T, class U>
 +
std::shared_ptr<T> reinterpret_pointer_cast(const std::shared_ptr<U>& r) noexcept
 +
{
 +
    auto p = reinterpret_cast<typename std::shared_ptr<T>::element_type*>(r.get());
 +
    return std::shared_ptr<T>{r, p};
 
}
 
}
 
}}
 
}}
Line 77: Line 102:
 
===Example===
 
===Example===
 
{{example
 
{{example
|
+
|code=
|code=
+
 
#include <iostream>
 
#include <iostream>
 
#include <memory>
 
#include <memory>
 
+
struct BaseClass {};
+
class Base
 
+
struct DerivedClass : BaseClass
+
 
{
 
{
     void f() const
+
public:
     {
+
    int a;
        std::cout << "Hello World!\n";
+
     virtual void f() const { std::cout << "I am base!\n"; }
     }
+
     virtual ~Base() {}
 +
};
 +
 +
class Derived : public Base
 +
{
 +
public:
 +
    void f() const override { std::cout << "I am derived!\n"; }
 +
     ~Derived() {}
 
};
 
};
  
 
int main()
 
int main()
 
{
 
{
     std::shared_ptr<BaseClass> ptr_to_base(std::make_shared<DerivedClass>());
+
     auto basePtr = std::make_shared<Base>();
 
+
    std::cout << "Base pointer says: ";
     // ptr_to_base->f(); // Error won't compile: BaseClass has no member named 'f'
+
     basePtr->f();
 
      
 
      
     std::static_pointer_cast<DerivedClass>(ptr_to_base)->f(); // OK
+
     auto derivedPtr = std::make_shared<Derived>();
     // (constructs a temporary shared_ptr, then calls operator->)
+
    std::cout << "Derived pointer says: ";
 
+
    derivedPtr->f();
     static_cast<DerivedClass*>(ptr_to_base.get())->f(); // also OK
+
   
     // (direct cast, does not construct a temporary shared_ptr)
+
     // 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';
 
}
 
}
|output=
+
|output=
Hello World!
+
Base pointer says: I am base!
Hello World!
+
Derived pointer says: I am derived!
 +
Base pointer to derived says: I am derived!
 +
Downcasted pointer says: I am derived!
 +
Pointers to underlying derived: 3
 
}}
 
}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
{{dsc inc | cpp/memory/shared_ptr/dsc constructor}}
+
{{dsc inc|cpp/memory/shared_ptr/dsc constructor}}
 
{{dsc end}}
 
{{dsc end}}
  
[[de:cpp/memory/shared ptr/pointer cast]]
+
{{langlinks|de|es|fr|it|ja|pt|ru|zh}}
[[es:cpp/memory/shared ptr/pointer cast]]
+
[[fr:cpp/memory/shared ptr/pointer cast]]
+
[[it:cpp/memory/shared ptr/pointer cast]]
+
[[ja:cpp/memory/shared ptr/pointer cast]]
+
[[pt:cpp/memory/shared ptr/pointer cast]]
+
[[ru:cpp/memory/shared ptr/pointer cast]]
+
[[zh:cpp/memory/shared ptr/pointer cast]]
+

Latest revision as of 06:58, 7 October 2023

 
 
Utilities library
General utilities
Relational operators (deprecated in C++20)
 
Dynamic memory management
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Allocators
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)



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

Creates a new instance of std::shared_ptr whose stored pointer is obtained from r's stored pointer using a cast expression.

If r is empty, so is the new shared_ptr (but its stored pointer is not necessarily null). Otherwise, the new shared_ptr will share ownership with the initial value of r, except that it is empty if the dynamic_cast performed by dynamic_pointer_cast returns a null pointer.

Let Y be typename std::shared_ptr<T>::element_type, then the resulting std::shared_ptr's stored pointer will be obtained by evaluating, respectively:

1,2) static_cast<Y*>(r.get())
3,4) dynamic_cast<Y*>(r.get()). If the result of the dynamic_cast is a null pointer value, the returned shared_ptr will be empty.
5,6) const_cast<Y*>(r.get())
7,8) reinterpret_cast<Y*>(r.get())

The behavior of these functions is undefined unless the corresponding cast from U* to T* is well formed:

1,2) The behavior is undefined unless static_cast<T*>((U*)nullptr) is well formed.
3,4) The behavior is undefined unless dynamic_cast<T*>((U*)nullptr) is well formed.
5,6) The behavior is undefined unless const_cast<T*>((U*)nullptr) is well formed.
7,8) The behavior is undefined unless reinterpret_cast<T*>((U*)nullptr) is well formed.

After calling the rvalue overloads (2,4,6,8), r is empty and r.get() == nullptr, except that r is not modified for dynamic_pointer_cast (4) if the dynamic_cast fails.

(since C++20)

Contents

[edit] Parameters

r - the pointer to convert

[edit] Notes

The expressions std::shared_ptr<T>(static_cast<T*>(r.get())), std::shared_ptr<T>(dynamic_cast<T*>(r.get())) and std::shared_ptr<T>(const_cast<T*>(r.get())) might seem to have the same effect, but they all will likely result in undefined behavior, attempting to delete the same object twice!

[edit] Possible implementation

static_pointer_cast
template<class T, class U>
std::shared_ptr<T> static_pointer_cast(const std::shared_ptr<U>& r) noexcept
{
    auto p = static_cast<typename std::shared_ptr<T>::element_type*>(r.get());
    return std::shared_ptr<T>{r, p};
}
dynamic_pointer_cast
template<class T, class U>
std::shared_ptr<T> dynamic_pointer_cast(const std::shared_ptr<U>& r) noexcept
{
    if (auto p = dynamic_cast<typename std::shared_ptr<T>::element_type*>(r.get()))
        return std::shared_ptr<T>{r, p};
    else
        return std::shared_ptr<T>{};
}
const_pointer_cast
template<class T, class U>
std::shared_ptr<T> const_pointer_cast(const std::shared_ptr<U>& r) noexcept
{
    auto p = const_cast<typename std::shared_ptr<T>::element_type*>(r.get());
    return std::shared_ptr<T>{r, p};
}
reinterpret_pointer_cast
template<class T, class U>
std::shared_ptr<T> reinterpret_pointer_cast(const std::shared_ptr<U>& r) noexcept
{
    auto p = reinterpret_cast<typename std::shared_ptr<T>::element_type*>(r.get());
    return std::shared_ptr<T>{r, p};
}

[edit] Example

#include <iostream>
#include <memory>
 
class Base
{
public:
    int a;
    virtual void f() const { std::cout << "I am base!\n"; }
    virtual ~Base() {}
};
 
class Derived : public Base
{
public:
    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';
}

Output:

Base pointer says: I am base!
Derived pointer says: I am derived!
Base pointer to derived says: I am derived!
Downcasted pointer says: I am derived!
Pointers to underlying derived: 3

[edit] See also

constructs new shared_ptr
(public member function) [edit]