This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: Weird (unintuitive?) behavior of std::tuple
- From: Alex Dubov <oakad at yahoo dot com>
- To: Tomasz Gajewski <tomga at wp dot pl>, Paolo Carlini <pcarlini at gmail dot com>
- Cc: "libstdc++ at gcc dot gnu dot org" <libstdc++ at gcc dot gnu dot org>
- Date: Sun, 31 Oct 2010 04:52:19 -0700 (PDT)
- Subject: Re: Weird (unintuitive?) behavior of std::tuple
--- On Sat, 30/10/10, Paolo Carlini <pcarlini@gmail.com> wrote:
>
> > Isn't it just that default copy constructors are
> called making copies of
> > objects so destructors are called twice: once for
> "original" object and
> > once for it's copy?
>
> Indeed. But this is the right reply for a message properly
> sent to gcc-help ;)
>
Indeed, the behavior of pair is identical (and, as such, counter-
intuitive). pair<B, C> xx(B(), C()) won't invoke the constructors at all,
just like tuple (but will invoke the non-default ones, if those were
specified). pair or tuple declared without initialization arguments will
invoke default constructors as expected.
I posted the question here because I was investigating Jonathan's
suggestion that tuple can be used as a storage container inside a
shared_ptr. When the tuple is constructed in-place with general user
object (constructor arguments being passed through variadic template
constructor) evil stuff happens, due to the behavior described above.
It seems, I have to revert to using alloc_hider style helper classes for
now, because I can't make tuple work correctly.
In my original usage case below, runtime errors will emerge for a wide
variety of user specified _Tp types. This means, that either tuple/pair
as currently implemented are unfit for such usage (and this should be
documented somehow) or the implementation should be considered buggy.
template<typename _Tp>
struct ref_count_val
{
template<typename... _Args>
ref_count_val(ref_count<_Tp> *__ref, _Args&&... __args)
: _M_ref(__ref), _M_v(std::forward<_Args>(__args)...)
{}
ref_count<_Tp> *_M_ref;
_Tp _M_v;
};
....
template<typename _Tp, typename _Alloc>
struct ref_count_a
{
template<typename... _Args>
ref_count_a(_Alloc __a, _Args&&... __args)
:_M_valplus(ref_count_val<_Tp>(this, std::forward<_Args>(__args)...),
std::forward<_Alloc>(__a))
{}
std::tuple<ref_count_val<_Tp>, _Alloc> _M_valplus;
};