[GSoC] Update on extend shared_ptr to support array

Jonathan Wakely jwakely@redhat.com
Tue Mar 24 12:55:00 GMT 2015

On 24/03/15 04:38 -0400, Fan You wrote:
>Here is a quick update of my work on extend shared_ptr to support
>array.(Finished basic constructor/function, weak_ptr support) I am
>getting familiar with libstdc++, and I'm trying to follow the coding
>style as close as possible. If there is any problems, please let me
>know! :-)

The formatting and style looks much beter now, thanks.

Have you submitted a formal GSoC proposal to Melange yet?  I have just
renewed my Melange account and applied to be a mentor again, so I
can't see the proposals until that is approved.

>Also, I have few questions:
>1. For all those entries list here
>do I need to implement them one by one into <experimental/memory>? Or,
>for those entries that can still be apply to shared_ptr array with no
>problem, can I just use them by including <memory> ?

Have you tested it?

I think you can just rely on the operators for the __shared_ptr base
class being found, and doing the right thing.

If it works without re-implementing each of them, great :-)

>2. Do I need to do a specialization for weak_ptr in shared_ptr_base.h
>to support shared_ptr_array? Even though the proposal didn't talk
>about it, I think it's necessary and I also made a few attempts on it.

Yes, I think you do need to do something, because
std::experimental::weak_ptr<T[]>::element_type should be T not T[]. It
doesn't have to be a specialization though, you could just change
std::__weak_ptr::element_type to use std::remove_extent, however ...

There's an issue I'd forgotten about which we should probably address:

In C++11 today, it is already possible to use std::shared_ptr<T[N]>,
although it's hard to use correctly and almost useless. For example,
this is valid in C++11:

  #include <memory>

  int main()
    int array[3];
    std::shared_ptr<int[3]> p(&array, [](void*){});

Although it's hard to use, this is technically valid and has clearly
defined semantics, which are different from
std::experimental::shared_ptr<int[3]>. In particular,
std::shared_ptr<int[3]>::element_type is int[3] but
std::experimental::shared_ptr<int[3]>::element_type is int.

(I'm not sure if a non-empty std::shared_ptr<T[]>, i.e. array of
unknown bound, can be used in C++11, so that might be even more

So while you're implementing the new semantics, we need to decide if
we want to continue supporting the old semantics (which are
technically required for C++11 conformance, but it's possible no-one
cares about that.)

I hope I've explained that clearly, let me know if I didn't.

I advised you to add a specialization of std::__shared_ptr<T[]>, so
that std::experimental::shared_ptr<T[]> would be simple to write and
most of the implementation would be in the __shared_ptr
specialization. That makes it impossible to support the old C++11
semantics, so it might not be the right approach (sorry!)

I can see at least three options:

(1) Ignore the C++11 requirements and just make __shared_ptr<T[]> and
    __shared_ptr<T[N]> meet the Fundamentals TS requirements. This
    would be the simplest option, but is not strictly conforming and
    carries some risk (C++17 might specify std::shared_ptr<T[]>
    differently from std::experimental::shared_ptr<T[]> and we'd have
    to change it again).

(2) Do not change __shared_ptr. Implement experimental::shared_ptr<T>
    by simply deriving from __shared_ptr<T>. Implement the array
    specializations experimental::shared_ptr<T[N]> and
    experimental::shared_ptr<T[]> by re-implementing them completely,
    without using __shared_ptr. That is quite a lot of work, and code
    duplication (you would need to write all the comparison operators
    again for the specializations).

(3) Add a specialization for __shared_ptr<__libfund_v1<T>> where
    __libfund_v1 is just a simple tag type like:

    template<typename _Tp>
      struct __libfund_v1 { using type = _Tp; };

    The __shared_ptr<__libfund_v1<>> specialization would implement
    the Fundamentals TS semantics, i.e. array support, then make
    experimental::shared_ptr<T[N]> derive from
    __shared_ptr<__libfund_v1<T[N]>> so it uses the specialization.
    This would allow us to isolate the different semantics required by
    the Library Fundamentals TS in the new specialization, not
    changing the behaviour of the C++11 shared_ptr template.

    We could also add the following alias template to allow people to
    use the new specialization directly (for people who want to use
    __shared_ptr<T[], LP> with a non-default lock policy):

    namespace std { namespace experimental {
      template<typename _Tp, _Lock_policy _Lp = __default_lock_policy>
        using __shared_ptr = std::__shared_ptr<__libfund_v1<_Tp>, _Lp>;
    } }

Any other suggestions?

I think it would be good to discuss this (and maybe experiment with
the different options) before doing too much more work that might go
in a wrong direction.

More information about the Libstdc++ mailing list