problem with std::forward_as_tuple in MIL

Discussion in 'C++' started by Frank Bergemann, Nov 20, 2011.

  1. Hi,
    i have problems to create and forward tuple in MIL (member
    initialization list).
    Here's the program:
    ------------------------------- snip
    --------------------------------------------------
    #include <iostream>
    #include <tuple>

    template <typename T>
    struct Elem
    {
    const T & _data;
    Elem(const T & inp)
    :_data(inp)
    { };

    Elem(const Elem &)
    {
    std::cout << "!!! Elem copy c'tor invoked !!!" << std::endl;
    };
    };

    template <typename T>
    std::eek:stream &
    operator<<(
    std::eek:stream & out,
    const Elem<T> & arg)
    {
    out << "Elem<T>(" << arg._data << ")";
    return out;
    }

    /* Host class to actually hold tuple<> */
    template <typename ...Types>
    struct HostClassImpl
    {
    typedef typename std::tuple<Elem<Types>&&...> Type;

    const Type _data;

    HostClassImpl(Type && data)
    : _data(data)
    { };

    HostClassImpl(const HostClassImpl &)
    {
    std::cout << "HostClassImpl copy c'tor!" << std::endl;
    };

    HostClassImpl & operator=(const HostClassImpl &)
    {
    std::cout << "HostClassImpl assignment operator!" << std::endl;
    return *this;
    };
    };

    /*
    * Host class front-end supporting variadic arguments
    * just to enable the user level to do without std::forward_as_tuple()
    * So HostClass actually shall do the std::forward_as_tuple() for the
    user.
    */
    template <typename ...Types>
    struct HostClass
    {
    HostClassImpl<Types...> _impl;

    template <typename ...Args>
    HostClass(
    Args&& ... args)
    : _impl(std::forward_as_tuple(args...))
    { };

    HostClass(const HostClass &)
    {
    std::cout << "HostClass copy c'tor!" << std::endl;
    };

    HostClass & operator=(const HostClass &)
    {
    std::cout << "HostClass assignment operator!" << std::endl;
    return *this;
    };
    };

    struct DummyHostClass
    {
    HostClassImpl<int, int, int> _impl;

    DummyHostClass(void)
    : _impl(std::forward_as_tuple(Elem<int>(10), Elem<int>(11),
    Elem<int>(12)))
    {
    log();
    };

    void log(void)
    {
    std::cout << "DummyHostClass log data:" << std::endl;
    std::cout << std::get<0>(_impl._data) << std::endl;
    std::cout << std::get<1>(_impl._data) << std::endl;
    std::cout << std::get<2>(_impl._data) << std::endl;
    }

    ~DummyHostClass()
    {
    std::cout << "DummyHostClass d'tor" << std::endl;
    };
    };

    int
    main(
    int argc,
    char ** argv)
    {

    std::cout << std::endl << "Test (1): use Elem<int> only:" <<
    std::endl;
    Elem<int> elem(5);
    std::cout << elem << std::endl;

    std::cout << std::endl << "Test (2): create tuple<Elem<int>&&> - one
    element only:" << std::endl;
    std::tuple<Elem<int>&&> tuple(std::forward_as_tuple(Elem<int>(3)));
    std::cout << std::get<0>(tuple) << std::endl;

    std::cout << std::endl << "Test (3): create tuple<Elem<int>&&>,
    Elem<int>&&> - two elements:" << std::endl;
    std::tuple<Elem<int>&&, Elem<int>&&>
    tuple2(std::forward_as_tuple(Elem<int>(5), Elem<int>(7)));
    std::cout << std::get<0>(tuple2) << std::endl;
    std::cout << std::get<1>(tuple2) << std::endl;

    std::cout << std::endl << "Test (4): use HostClassImpl::Type
    defnition for tuple<Elem<int>&&, Elem<int>&&> - two elements:" <<
    std::endl;
    HostClassImpl<int,int>::Type
    tuple3(std::forward_as_tuple(Elem<int>(8), Elem<int>(9)));
    std::cout << std::get<0>(tuple3) << std::endl;
    std::cout << std::get<1>(tuple3) << std::endl;

    std::cout << std::endl << "Test (5): use HostClassImpl c'tor passing
    already constructed tuple:" << std::endl;
    HostClassImpl<int, int> hostImpl(std::forward_as_tuple(Elem<int>(10),
    Elem<int>(11)));
    std::cout << std::get<0>(hostImpl._data) << std::endl;
    std::cout << std::get<1>(hostImpl._data) << std::endl;

    std::cout << std::endl << "Test (6): use DummyHostClass with fixed
    HostClassImpl within:" << std::endl;
    DummyHostClass dummy;
    dummy.log();

    #if 0
    std::cout << std::endl << "Test (7): use HostClass c'tor passing
    individual tuple element (variadic template):" << std::endl;
    HostClass<int, int> host(Elem<int>(12), Elem<int>(13));
    std::cout << std::get<0>(host._impl._data) << std::endl;
    std::cout << std::get<1>(host._impl._data) << std::endl;
    #endif

    return 0;
    }
    ------------------------------- snap
    --------------------------------------------------

    Here's the output:

    ------------------------------- snip
    --------------------------------------------------
    > ./main


    Test (1): use Elem<int> only:
    Elem<T>(5)

    Test (2): create tuple<Elem<int>&&> - one element only:
    Elem<T>(3)

    Test (3): create tuple<Elem<int>&&>, Elem<int>&&> - two elements:
    Elem<T>(5)
    Elem<T>(7)

    Test (4): use HostClassImpl::Type defnition for tuple<Elem<int>&&,
    Elem<int>&&> - two elements:
    Elem<T>(8)
    Elem<T>(9)

    Test (5): use HostClassImpl c'tor passing already constructed tuple:
    Elem<T>(10)
    Elem<T>(11)

    Test (6): use DummyHostClass with fixed HostClassImpl within:
    DummyHostClass log data:
    Elem<T>(10)
    Elem<T>(11)
    Elem<T>(12)
    DummyHostClass log data:
    Elem<T>(10)
    Elem<T>(11871724)
    Elem<T>(-1079275032)
    DummyHostClass d'tor

    ------------------------------- snap
    --------------------------------------------------

    Why it the data away after leaving the constructor of DummyHostClass?
    (Btw: 'DummyHostClass' is just a step towards intented 'HostClass' to
    localize the problem.)

    - many thanks!

    best regards,
    Frank
    Frank Bergemann, Nov 20, 2011
    #1
    1. Advertising

  2. Frank Bergemann

    SG Guest

    On Nov 20, 3:28 pm, Frank Bergemann wrote:
    > [...]
    > Why it the data away after leaving the constructor of DummyHostClass?
    > (Btw: 'DummyHostClass' is just a step towards intented 'HostClass' to
    > localize the problem.)


    I just skimmed Elem<> and HostClassImpl<> and stopped right there.
    What is the point of all this? What are you actually trying to achieve
    here? What is the point of Elem? It just wraps a reference. What is
    the point of HostClassImpl? It just wraps a tuple of rvalue references
    to Elem objects which itself wrap lvalue references. Surely this is
    not what you want. That much I can tell you...

    The first couple of lines of main already invoke undefined behaviour:

    1 cout << "\nTest (1): use Elem<int> only:" << endl;
    2 Elem<int> elem(5);
    3 cout << elem << endl;

    During execution of line 2 a temporary int object will be created and
    initialized with 5 and it will be destroyed immeadately when execution
    reaches the semicolon. Since Elem is defined like this:

    template <typename T>
    struct Elem
    {
    const T & _data;
    Elem(const T & inp)
    :_data(inp) {}
    };

    the object called 'elem' will store a dangling reference to an int-
    object that does not exist anymore beyond line 2. Accessing this non-
    existing int-object in line 3 invokes undefined behaviour.

    You should avoid the use of references, *especially* rvalue
    references, if you don't know what you are doing.

    Cheers!
    SG
    SG, Nov 21, 2011
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page