Search code examples
c++arraysc++17shared-ptrsmart-pointers

Detect that std::shared_ptr is holding a raw array (and obtaining its size)


I'm working on (yet another) C++ serialization library that supports standard types such as containers. In particular I want to support smart pointers.

C++17 introduced support for std::shared_ptr holding raw arrays (it knows to invoke delete [] in such cases). I need to detect that the shared_ptr is holding a raw array so that I can serialize it accordingly:

template <typename T>
void serialize(Writer& writer, const std::shared_ptr<T> ptr)
{
    // Writer has overloaded operator()

    if (ptr)
    {
        if (holdsRawArray(ptr)) // How to implement this???
        {
            auto arrayWriter = writer.array(); // RAII
            auto size = rawArraySize(ptr); // How to get this???
            for (std::size_t i=0; i<size; ++i) 
                arrayWriter(ptr[i]);
        }
        else
            writer(*ptr);
    }
    else
        writer(null);
}

How do I determine that a C++17 smart pointer contains a raw array? This information is erased in the element_type member typedef (via std::remove_extent_t). I also can't find anything in the smart pointer API that would reveal the size of the raw array.

I thought about using the detector idiom on operator[] and operator*, but it appears implementations are not required to undefine them if T is or isn't a raw array.

Is what I'm attempting even possible? I'm hoping I missed something, or that there's some trick I could use.

I know I can force users to use std::shared_ptr<std::array<N,T>> or std::shared_ptr<std::vector<T>> instead, but I just want to check if it's even possible for me to support smart pointers holding raw arrays.


Solution

  • You can determine if shared_ptr holds an array type by checking if T is an array type using compile-time type traits. It is even implemented in std.

    if constexpr (std::is_array_v<T>)
    

    But there is no way to get the size because it is allocated dynamically and not stored anywhere.