Namespaces
Variants
Views
Actions

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

From cppreference.com
< cpp‎ | memory‎ | shared ptr
m (grammar)
m ({{c}}, @-@ -> @,@)
 
(25 intermediate revisions by 16 users not shown)
Line 1: Line 1:
{{cpp/title | static_pointer_cast | dynamic_pointer_cast | const_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=
shared_ptr<T> static_pointer_cast( const 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 >
shared_ptr<T> dynamic_pointer_cast( const 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 >
shared_ptr<T> const_pointer_cast( const shared_ptr<U>& r );
+
std::shared_ptr<T> dynamic_pointer_cast( const std::shared_ptr<U>& r ) noexcept;
 +
}}
 +
{{dcl|num=4|since=c++20|1=
 +
template< class T, class U >
 +
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 managed object type is obtained from the {{tt|r}}'s managed object type using a cast expression. Both smart pointers will share the ownership of the managed object.
+
Creates a new instance of {{lc|std::shared_ptr}} whose stored pointer is obtained from {{c|r}}'s stored pointer using a cast expression.
  
The resulting {{lc|std::shared_ptr}}'s managed object will be obtained by calling (in respective order):
+
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.
  
@1@ {{tt|static_cast<T*>(r.get())}}.
+
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:
  
@2@ {{tt|dynamic_cast<T*>(r.get())}} (If the result of the {{tt|dynamic_cast}} is 0, the returned shared_ptr will be empty).
+
@1,2@ {{c|static_cast<Y*>(r.get())}}
 +
@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.
 +
@5,6@ {{c|const_cast<Y*>(r.get())}}
 +
@7,8@ {{c|reinterpret_cast<Y*>(r.get())}}
  
@3@ {{tt|const_cast<T*>(r.get())}}.
+
The behavior of these functions is undefined unless the corresponding cast from {{tt|U*}} to {{tt|T*}} is well formed:
  
In any case, if the parameter {{tt|r}} is an empty {{lc|std::shared_ptr}} the result will be a new empty {{lc|std::shared_ptr}}.
+
@1,2@ The behavior is undefined unless {{c|static_cast<T*>((U*)nullptr)}} is well formed.
 +
@3,4@ The behavior is undefined unless {{c|dynamic_cast<T*>((U*)nullptr)}} is well formed.
 +
@5,6@ The behavior is undefined unless {{c|const_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===
+
===Notes===
{{noexcept}}
+
The expressions {{c|std::shared_ptr<T>(static_cast<T*>(r.get()))}}, {{c|std::shared_ptr<T>(dynamic_cast<T*>(r.get()))}} and {{c|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!
 +
 
 +
===Possible implementation===
 +
{{eq impl
 +
|title1=static_pointer_cast|ver1=1|1=
 +
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};
 +
}
 +
|title2=dynamic_pointer_cast|ver2=3|2=
 +
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>{};
 +
}
 +
|title3=const_pointer_cast|ver3=5|3=
 +
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};
 +
}
 +
|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};
 +
}
 +
}}
 +
 
 +
===Example===
 +
{{example
 +
|code=
 +
#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
 +
}}
 +
 
 +
===See also===
 +
{{dsc begin}}
 +
{{dsc inc|cpp/memory/shared_ptr/dsc constructor}}
 +
{{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]