[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:
>Hello,
>
>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
><http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4335.html#header.memory.synop>,
>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
useless).

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