What's your preferred way of returning a list of items?

Discussion in 'C++' started by DeMarcus, May 12, 2010.

  1. DeMarcus

    DeMarcus Guest

    Hi,

    Here are a couple of ways to return some list of items.

    struct A
    {
    };

    std::vector<A> aList; // Some list of items.

    // Returning a copy.
    std::vector<A> getList() { return aList; }

    void getList( std::vector<A>& v )
    {
    std::copy( aList.begin(), aList.end(), v.begin() );
    }

    void getList( std::vector<A>* v )
    {
    std::copy( aList.begin(), aList.end(), v->begin() );
    }

    // Returning a reference to aList.
    const std::vector<A>& getList() { return aList; }

    const std::vector<A>::const_iterator& getList()
    {
    return aList.begin();
    }

    Do you know more ways to return a list? What's your preferred way to
    return a list of items?




    Also, here comes another trickier one. Let's say I have a map instead
    and want to return the keys.

    std::map<std::string, A> aMap;

    // Returning a copy of the keys.
    std::vector<std::string> getList()
    {
    std::vector<std::string> aKeys;
    auto keysEnd = aMap.end();
    for( auto i = aMap.begin(); i != keysEnd; ++i )
    aKeys.push_back( (*i).first );
    return aKeys;
    }

    void getList( std::vector<std::string>& v )
    {
    auto keysEnd = aMap.end();
    for( auto i = aMap.begin(); i != keysEnd; ++i )
    v.push_back( (*i).first );
    }

    void getList( std::vector<std::string>* v )
    {
    auto keysEnd = aMap.end();
    for( auto i = aMap.begin(); i != keysEnd; ++i )
    v->push_back( (*i).first );
    }


    // But is it even possible to return a reference to
    // the keys in a map?

    const std::vector<std::string>& getList() { /* What here? */ }

    const std::vector<std::string>::const_iterator& getList()
    {
    /* What here? */
    }


    How do you usually deal with these kind of list returns?



    Thanks,
    Daniel
    DeMarcus, May 12, 2010
    #1
    1. Advertising

  2. DeMarcus

    Kai-Uwe Bux Guest

    DeMarcus wrote:

    > Hi,
    >
    > Here are a couple of ways to return some list of items.
    >
    > struct A
    > {
    > };
    >
    > std::vector<A> aList; // Some list of items.
    >
    > // Returning a copy.
    > std::vector<A> getList() { return aList; }
    >
    > void getList( std::vector<A>& v )
    > {
    > std::copy( aList.begin(), aList.end(), v.begin() );
    > }
    >
    > void getList( std::vector<A>* v )
    > {
    > std::copy( aList.begin(), aList.end(), v->begin() );
    > }
    >
    > // Returning a reference to aList.
    > const std::vector<A>& getList() { return aList; }
    >
    > const std::vector<A>::const_iterator& getList()
    > {
    > return aList.begin();
    > }
    >
    > Do you know more ways to return a list? What's your preferred way to
    > return a list of items?


    I often use output iterators. So, my function signature looks as follows:

    template < typename OutIter >
    OutIter get_items ( OutIter where, other args );

    That way, the client can decide which data structure should be used when the
    items are to be stored.

    > Also, here comes another trickier one. Let's say I have a map instead
    > and want to return the keys.
    >
    > std::map<std::string, A> aMap;
    >
    > // Returning a copy of the keys.
    > std::vector<std::string> getList()
    > {
    > std::vector<std::string> aKeys;
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > aKeys.push_back( (*i).first );
    > return aKeys;
    > }
    >
    > void getList( std::vector<std::string>& v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v.push_back( (*i).first );
    > }
    >
    > void getList( std::vector<std::string>* v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v->push_back( (*i).first );
    > }
    >
    >
    > // But is it even possible to return a reference to
    > // the keys in a map?
    >
    > const std::vector<std::string>& getList() { /* What here? */ }
    >
    > const std::vector<std::string>::const_iterator& getList()
    > {
    > /* What here? */
    > }
    >
    >
    > How do you usually deal with these kind of list returns?


    See above.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, May 12, 2010
    #2
    1. Advertising

  3. DeMarcus

    Öö Tiib Guest

    On May 12, 11:18 am, DeMarcus <> wrote:
    > Hi,
    >
    > Here are a couple of ways to return some list of items.
    >
    > struct A
    > {
    >
    > };
    >
    > std::vector<A> aList;  // Some list of items.
    >
    > // Returning a copy.
    > std::vector<A> getList() { return aList; }
    >
    > void getList( std::vector<A>& v )
    > {
    >     std::copy( aList.begin(), aList.end(), v.begin() );
    >
    > }
    >
    > void getList( std::vector<A>* v )
    > {
    >     std::copy( aList.begin(), aList.end(), v->begin() );
    >
    > }
    >
    > // Returning a reference to aList.
    > const std::vector<A>& getList() { return aList; }
    >
    > const std::vector<A>::const_iterator& getList()
    > {
    >     return aList.begin();
    >
    > }
    >
    > Do you know more ways to return a list? What's your preferred way to
    > return a list of items?
    >
    > Also, here comes another trickier one. Let's say I have a map instead
    > and want to return the keys.
    >
    > std::map<std::string, A> aMap;
    >
    > // Returning a copy of the keys.
    > std::vector<std::string> getList()
    > {
    >     std::vector<std::string> aKeys;
    >     auto keysEnd = aMap.end();
    >     for( auto i = aMap.begin(); i != keysEnd; ++i )
    >        aKeys.push_back( (*i).first );
    >     return aKeys;
    >
    > }
    >
    > void getList( std::vector<std::string>& v )
    > {
    >     auto keysEnd = aMap.end();
    >     for( auto i = aMap.begin(); i != keysEnd; ++i )
    >        v.push_back( (*i).first );
    >
    > }
    >
    > void getList( std::vector<std::string>* v )
    > {
    >     auto keysEnd = aMap.end();
    >     for( auto i = aMap.begin(); i != keysEnd; ++i )
    >        v->push_back( (*i).first );
    >
    > }
    >
    > // But is it even possible to return a reference to
    > // the keys in a map?
    >
    > const std::vector<std::string>& getList() { /* What here? */ }
    >
    > const std::vector<std::string>::const_iterator& getList()
    > {
    >     /* What here? */
    >
    > }
    >
    > How do you usually deal with these kind of list returns?


    Usually...

    I avoid writing functions that are getters, copiers or even worse ...
    setters, because these indicate lousy design. I usually try my best to
    have interface that allows operations that make sense to do with the
    objects of given type and not interface that allows mechanical
    setting, getting and copying of the properties of objects.

    My functions that are still getters are nouns (remove "get" prefix,
    once situation enforces to be lousy, go maximum) and are either
    returning copies or const references. My functions that fill their
    parameters with a copy of internal data start with "copy" and i call
    them copiers. Setters are also nouns (no "set" prefix; have to be java
    so go maximum) but return void and take const reference as parameter.

    I call std::vector as "a vector" and std::list as "a list". There are
    no further deep reasons for such conventions; one just has to stick to
    something over years.
    Öö Tiib, May 12, 2010
    #3
  4. On 12.05.2010 10:18, * DeMarcus:
    > Hi,
    >
    > Here are a couple of ways to return some list of items.
    >
    > struct A
    > {
    > };
    >
    > std::vector<A> aList; // Some list of items.
    >
    > // Returning a copy.
    > std::vector<A> getList() { return aList; }


    This one is OK, and will be efficient with modern compiler.


    > void getList( std::vector<A>& v )
    > {
    > std::copy( aList.begin(), aList.end(), v.begin() );
    > }


    This one's signature is OK as an opt-in alternative to the first one (i.e.
    provide /both/, or just the first one).

    However, the implementation is incorrect unless you assume that the argument is
    of exactly the right size for the result (and that assumption would be
    unrealistic, to put it mildly).

    You could write it like

    void getList( std::vector< A >& v )
    {
    std::vector< A >( aList.begin(), aList.end() ).swap( v );
    }



    > void getList( std::vector<A>* v )
    > {
    > std::copy( aList.begin(), aList.end(), v->begin() );
    > }


    This one is just bad. Why would you want to support nullpointer argument? If
    someone calls 'getList' it's in order to get that list, not in order to do nothing.

    Anyway, under normal assumptions the implementation is incorrect.


    > // Returning a reference to aList.
    > const std::vector<A>& getList() { return aList; }


    This one's OK if you're clear on what it does.



    > const std::vector<A>::const_iterator& getList()
    > {
    > return aList.begin();
    > }


    This is one is just silly, the caller can't do anything reasonable with the
    returned iterator.


    > Do you know more ways to return a list?


    How about ways to return lists, instead of vectors (arrays)?




    > What's your preferred way to
    > return a list of items?


    That doesn't make sense without a lot more explanation of exactly what you mean
    by "list" and in what context you'd want to return -- what?


    > Also, here comes another trickier one. Let's say I have a map instead
    > and want to return the keys.
    >
    > std::map<std::string, A> aMap;
    >
    > // Returning a copy of the keys.
    > std::vector<std::string> getList()
    > {
    > std::vector<std::string> aKeys;
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > aKeys.push_back( (*i).first );
    > return aKeys;
    > }
    >
    > void getList( std::vector<std::string>& v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v.push_back( (*i).first );
    > }
    >
    > void getList( std::vector<std::string>* v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v->push_back( (*i).first );
    > }
    >
    >
    > // But is it even possible to return a reference to
    > // the keys in a map?
    >
    > const std::vector<std::string>& getList() { /* What here? */ }
    >
    > const std::vector<std::string>::const_iterator& getList()
    > {
    > /* What here? */
    > }


    How about defining an iterator that walks through the keys. Then you don't have
    to create all those string objects.


    > How do you usually deal with these kind of list returns?


    Sorry, again the question is to vague to be meaningful to me.

    But see above.


    Cheers & hth.,

    - Alf
    (blog at <url: http://alfps.wordpress.com>)
    Alf P. Steinbach, May 12, 2010
    #4
  5. DeMarcus

    DeMarcus Guest

    Öö Tiib wrote:
    > On May 12, 11:18 am, DeMarcus <> wrote:
    >> Hi,
    >>
    >> Here are a couple of ways to return some list of items.
    >>
    >> struct A
    >> {
    >>
    >> };
    >>
    >> std::vector<A> aList; // Some list of items.
    >>
    >> // Returning a copy.
    >> std::vector<A> getList() { return aList; }
    >>
    >> void getList( std::vector<A>& v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v.begin() );
    >>
    >> }
    >>
    >> void getList( std::vector<A>* v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v->begin() );
    >>
    >> }
    >>
    >> // Returning a reference to aList.
    >> const std::vector<A>& getList() { return aList; }
    >>
    >> const std::vector<A>::const_iterator& getList()
    >> {
    >> return aList.begin();
    >>
    >> }
    >>
    >> Do you know more ways to return a list? What's your preferred way to
    >> return a list of items?
    >>
    >> Also, here comes another trickier one. Let's say I have a map instead
    >> and want to return the keys.
    >>
    >> std::map<std::string, A> aMap;
    >>
    >> // Returning a copy of the keys.
    >> std::vector<std::string> getList()
    >> {
    >> std::vector<std::string> aKeys;
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> aKeys.push_back( (*i).first );
    >> return aKeys;
    >>
    >> }
    >>
    >> void getList( std::vector<std::string>& v )
    >> {
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> v.push_back( (*i).first );
    >>
    >> }
    >>
    >> void getList( std::vector<std::string>* v )
    >> {
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> v->push_back( (*i).first );
    >>
    >> }
    >>
    >> // But is it even possible to return a reference to
    >> // the keys in a map?
    >>
    >> const std::vector<std::string>& getList() { /* What here? */ }
    >>
    >> const std::vector<std::string>::const_iterator& getList()
    >> {
    >> /* What here? */
    >>
    >> }
    >>
    >> How do you usually deal with these kind of list returns?

    >
    > Usually...
    >
    > I avoid writing functions that are getters, copiers or even worse ...
    > setters, because these indicate lousy design. I usually try my best to
    > have interface that allows operations that make sense to do with the
    > objects of given type and not interface that allows mechanical
    > setting, getting and copying of the properties of objects.
    >


    Ok, great. Actually I'm also very considered with clean design, but
    sometimes I find it impossible to do anything else than returning a
    container.

    I'm playing around with a command in Linux called backtrace_symbols. The
    command gives you the stack trace. Now I want to wrap that somehow and
    this is what I've made so far.

    std::vector<std::string> getStackTrace();

    How would you do this? Like this

    std::vector<std::string> stackTrace();

    or provide functions that can be applied to the stack trace, e.g.

    std::eek:stream& operator<<( std::eek:stream&, const StackTrace& );

    or something else?
    DeMarcus, May 12, 2010
    #5
  6. DeMarcus

    DeMarcus Guest

    Alf P. Steinbach wrote:
    > On 12.05.2010 10:18, * DeMarcus:
    >> Hi,
    >>
    >> Here are a couple of ways to return some list of items.
    >>
    >> struct A
    >> {
    >> };
    >>
    >> std::vector<A> aList; // Some list of items.
    >>
    >> // Returning a copy.
    >> std::vector<A> getList() { return aList; }

    >
    > This one is OK, and will be efficient with modern compiler.
    >
    >
    >> void getList( std::vector<A>& v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v.begin() );
    >> }

    >
    > This one's signature is OK as an opt-in alternative to the first one
    > (i.e. provide /both/, or just the first one).
    >
    > However, the implementation is incorrect unless you assume that the
    > argument is of exactly the right size for the result (and that
    > assumption would be unrealistic, to put it mildly).
    >
    > You could write it like
    >
    > void getList( std::vector< A >& v )
    > {
    > std::vector< A >( aList.begin(), aList.end() ).swap( v );
    > }
    >


    That's nice! Where do I find tricks like that? I don't find such things
    in Josuttis' book.

    >> void getList( std::vector<A>* v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v->begin() );
    >> }

    >
    > This one is just bad. Why would you want to support nullpointer
    > argument? If someone calls 'getList' it's in order to get that list, not
    > in order to do nothing.
    >


    I just listed all I could come to think of.


    >> // Returning a reference to aList.
    >> const std::vector<A>& getList() { return aList; }

    >
    > This one's OK if you're clear on what it does.
    >
    >
    >
    >> const std::vector<A>::const_iterator& getList()
    >> {
    >> return aList.begin();
    >> }

    >
    > This is one is just silly, the caller can't do anything reasonable with
    > the returned iterator.
    >
    >
    >> Do you know more ways to return a list?

    >
    > How about ways to return lists, instead of vectors (arrays)?
    >


    Lists are fine too, are there notable differences between returning a
    vector and a list?


    >> What's your preferred way to
    >> return a list of items?

    >
    > That doesn't make sense without a lot more explanation of exactly what
    > you mean by "list" and in what context you'd want to return -- what?
    >
    >


    Here's an example I gave Öö Tiib.

    I'm playing around with a command in Linux called backtrace_symbols. The
    command gives you the stack trace. Now I want to wrap that somehow and
    this is what I've made so far.

    std::vector<std::string> getStackTrace();

    How would you do that?


    >> Also, here comes another trickier one. Let's say I have a map instead
    >> and want to return the keys.
    >>
    >> std::map<std::string, A> aMap;
    >>
    >> // Returning a copy of the keys.
    >> std::vector<std::string> getList()
    >> {
    >> std::vector<std::string> aKeys;
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> aKeys.push_back( (*i).first );
    >> return aKeys;
    >> }
    >>
    >> void getList( std::vector<std::string>& v )
    >> {
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> v.push_back( (*i).first );
    >> }
    >>
    >> void getList( std::vector<std::string>* v )
    >> {
    >> auto keysEnd = aMap.end();
    >> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >> v->push_back( (*i).first );
    >> }
    >>
    >>
    >> // But is it even possible to return a reference to
    >> // the keys in a map?
    >>
    >> const std::vector<std::string>& getList() { /* What here? */ }
    >>
    >> const std::vector<std::string>::const_iterator& getList()
    >> {
    >> /* What here? */
    >> }

    >
    > How about defining an iterator that walks through the keys. Then you
    > don't have to create all those string objects.
    >
    >


    Please show, I need to enhance my skills. It feels right now that I'm
    just using the basic methods.
    DeMarcus, May 12, 2010
    #6
  7. DeMarcus

    Sousuke Guest

    On May 12, 3:18 am, DeMarcus <> wrote:
    > Hi,
    >
    > Here are a couple of ways to return some list of items.
    >
    > struct A
    > {
    >
    > };
    >
    > std::vector<A> aList;  // Some list of items.
    >
    > // Returning a copy.
    > std::vector<A> getList() { return aList; }
    >
    > void getList( std::vector<A>& v )
    > {
    >     std::copy( aList.begin(), aList.end(), v.begin() );


    Isn't that just a more complicated and unsafe way of doing:

    v = aList;

    ?

    > }
    >
    > void getList( std::vector<A>* v )
    > {
    >     std::copy( aList.begin(), aList.end(), v->begin() );
    >
    > }


    I recently started a thread on that subject (whether "out" parameters
    should be pointers instead of references):

    http://groups.google.com/group/comp.lang.c /browse_thread/thread/697f5fbff47a94e3#

    It seems most agreed that it's a dumb guideline.

    > // Returning a reference to aList.
    > const std::vector<A>& getList() { return aList; }


    That's the preffered way if the object being returned is a member of a
    class (which means that the method is just a simple accessor
    (getter)). More generally, it's ok as long as the object's lifetime is
    well-defined and known to the caller (in the case of a member
    variable, the lifetime is the same as that of its containing object).

    > const std::vector<A>::const_iterator& getList()
    > {
    >     return aList.begin();
    >
    > }


    Seems pointless.

    > Do you know more ways to return a list? What's your preferred way to
    > return a list of items?


    Either "vector<A> getList()" or "void getList(vector<A>&)" if I need
    copying, or "const vector<A>& getList() const" (and possibly a non-
    const overload) if the returned object is a member variable.
    Sousuke, May 12, 2010
    #7
  8. DeMarcus

    Jeff Flinn Guest

    DeMarcus wrote:
    > Öö Tiib wrote:
    >> On May 12, 11:18 am, DeMarcus <> wrote:
    >>> Hi,
    >>>
    >>> Here are a couple of ways to return some list of items.
    >>>
    >>> struct A
    >>> {
    >>>
    >>> };
    >>>
    >>> std::vector<A> aList; // Some list of items.
    >>>
    >>> // Returning a copy.
    >>> std::vector<A> getList() { return aList; }
    >>>
    >>> void getList( std::vector<A>& v )
    >>> {
    >>> std::copy( aList.begin(), aList.end(), v.begin() );
    >>>
    >>> }
    >>>
    >>> void getList( std::vector<A>* v )
    >>> {
    >>> std::copy( aList.begin(), aList.end(), v->begin() );
    >>>
    >>> }
    >>>
    >>> // Returning a reference to aList.
    >>> const std::vector<A>& getList() { return aList; }
    >>>
    >>> const std::vector<A>::const_iterator& getList()
    >>> {
    >>> return aList.begin();
    >>>
    >>> }
    >>>
    >>> Do you know more ways to return a list? What's your preferred way to
    >>> return a list of items?
    >>>
    >>> Also, here comes another trickier one. Let's say I have a map instead
    >>> and want to return the keys.
    >>>
    >>> std::map<std::string, A> aMap;
    >>>
    >>> // Returning a copy of the keys.
    >>> std::vector<std::string> getList()
    >>> {
    >>> std::vector<std::string> aKeys;
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> aKeys.push_back( (*i).first );
    >>> return aKeys;
    >>>
    >>> }
    >>>
    >>> void getList( std::vector<std::string>& v )
    >>> {
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> v.push_back( (*i).first );
    >>>
    >>> }
    >>>
    >>> void getList( std::vector<std::string>* v )
    >>> {
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> v->push_back( (*i).first );
    >>>
    >>> }
    >>>
    >>> // But is it even possible to return a reference to
    >>> // the keys in a map?
    >>>
    >>> const std::vector<std::string>& getList() { /* What here? */ }
    >>>
    >>> const std::vector<std::string>::const_iterator& getList()
    >>> {
    >>> /* What here? */
    >>>
    >>> }
    >>>
    >>> How do you usually deal with these kind of list returns?

    >>
    >> Usually...
    >>
    >> I avoid writing functions that are getters, copiers or even worse ...
    >> setters, because these indicate lousy design. I usually try my best to
    >> have interface that allows operations that make sense to do with the
    >> objects of given type and not interface that allows mechanical
    >> setting, getting and copying of the properties of objects.
    >>

    >
    > Ok, great. Actually I'm also very considered with clean design, but
    > sometimes I find it impossible to do anything else than returning a
    > container.
    >
    > I'm playing around with a command in Linux called backtrace_symbols. The
    > command gives you the stack trace. Now I want to wrap that somehow and
    > this is what I've made so far.
    >
    > std::vector<std::string> getStackTrace();
    >
    > How would you do this? Like this
    >
    > std::vector<std::string> stackTrace();
    >
    > or provide functions that can be applied to the stack trace, e.g.
    >
    > std::eek:stream& operator<<( std::eek:stream&, const StackTrace& );


    Your implication here of a StackTrace class would be my choice. Along
    with StackTraceItem class and whatever other classes embody the domain
    entities. Then as you've shown each of these classes could be
    streamable. The StackTrace class could then provide a container
    interface including the expected typedefs, iterators and methods.

    Jeff
    Jeff Flinn, May 12, 2010
    #8
  9. DeMarcus

    DeMarcus Guest

    Jeff Flinn wrote:
    > DeMarcus wrote:
    >> Öö Tiib wrote:
    >>> On May 12, 11:18 am, DeMarcus <> wrote:
    >>>> Hi,
    >>>>
    >>>> Here are a couple of ways to return some list of items.
    >>>>
    >>>> struct A
    >>>> {
    >>>>
    >>>> };
    >>>>
    >>>> std::vector<A> aList; // Some list of items.
    >>>>
    >>>> // Returning a copy.
    >>>> std::vector<A> getList() { return aList; }
    >>>>
    >>>> void getList( std::vector<A>& v )
    >>>> {
    >>>> std::copy( aList.begin(), aList.end(), v.begin() );
    >>>>
    >>>> }
    >>>>
    >>>> void getList( std::vector<A>* v )
    >>>> {
    >>>> std::copy( aList.begin(), aList.end(), v->begin() );
    >>>>
    >>>> }
    >>>>
    >>>> // Returning a reference to aList.
    >>>> const std::vector<A>& getList() { return aList; }
    >>>>
    >>>> const std::vector<A>::const_iterator& getList()
    >>>> {
    >>>> return aList.begin();
    >>>>
    >>>> }
    >>>>
    >>>> Do you know more ways to return a list? What's your preferred way to
    >>>> return a list of items?
    >>>>
    >>>> Also, here comes another trickier one. Let's say I have a map instead
    >>>> and want to return the keys.
    >>>>
    >>>> std::map<std::string, A> aMap;
    >>>>
    >>>> // Returning a copy of the keys.
    >>>> std::vector<std::string> getList()
    >>>> {
    >>>> std::vector<std::string> aKeys;
    >>>> auto keysEnd = aMap.end();
    >>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>> aKeys.push_back( (*i).first );
    >>>> return aKeys;
    >>>>
    >>>> }
    >>>>
    >>>> void getList( std::vector<std::string>& v )
    >>>> {
    >>>> auto keysEnd = aMap.end();
    >>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>> v.push_back( (*i).first );
    >>>>
    >>>> }
    >>>>
    >>>> void getList( std::vector<std::string>* v )
    >>>> {
    >>>> auto keysEnd = aMap.end();
    >>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>> v->push_back( (*i).first );
    >>>>
    >>>> }
    >>>>
    >>>> // But is it even possible to return a reference to
    >>>> // the keys in a map?
    >>>>
    >>>> const std::vector<std::string>& getList() { /* What here? */ }
    >>>>
    >>>> const std::vector<std::string>::const_iterator& getList()
    >>>> {
    >>>> /* What here? */
    >>>>
    >>>> }
    >>>>
    >>>> How do you usually deal with these kind of list returns?
    >>>
    >>> Usually...
    >>>
    >>> I avoid writing functions that are getters, copiers or even worse ...
    >>> setters, because these indicate lousy design. I usually try my best to
    >>> have interface that allows operations that make sense to do with the
    >>> objects of given type and not interface that allows mechanical
    >>> setting, getting and copying of the properties of objects.
    >>>

    >>
    >> Ok, great. Actually I'm also very considered with clean design, but
    >> sometimes I find it impossible to do anything else than returning a
    >> container.
    >>
    >> I'm playing around with a command in Linux called backtrace_symbols.
    >> The command gives you the stack trace. Now I want to wrap that somehow
    >> and this is what I've made so far.
    >>
    >> std::vector<std::string> getStackTrace();
    >>
    >> How would you do this? Like this
    >>
    >> std::vector<std::string> stackTrace();
    >>
    >> or provide functions that can be applied to the stack trace, e.g.
    >>
    >> std::eek:stream& operator<<( std::eek:stream&, const StackTrace& );

    >
    > Your implication here of a StackTrace class would be my choice. Along
    > with StackTraceItem class and whatever other classes embody the domain
    > entities. Then as you've shown each of these classes could be
    > streamable. The StackTrace class could then provide a container
    > interface including the expected typedefs, iterators and methods.
    >
    > Jeff
    >


    I agree with you that one should not be afraid of making classes of even
    the simplest things. But sometimes I just feel to be lazy, and in this
    case the stack trace is just a list of text, so just to get up running
    with a decent solution I chose to just provide a container.

    Then came my mind block; I always return something like
    std::vector<std::string>, but is that the best way to return a
    container? How are containers returned with the new C++0x rvalue
    reference for instance?
    DeMarcus, May 12, 2010
    #9
  10. DeMarcus

    DeMarcus Guest

    Sousuke wrote:
    > On May 12, 3:18 am, DeMarcus <> wrote:
    >> Hi,
    >>
    >> Here are a couple of ways to return some list of items.
    >>
    >> struct A
    >> {
    >>
    >> };
    >>
    >> std::vector<A> aList; // Some list of items.
    >>
    >> // Returning a copy.
    >> std::vector<A> getList() { return aList; }
    >>
    >> void getList( std::vector<A>& v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v.begin() );

    >
    > Isn't that just a more complicated and unsafe way of doing:
    >
    > v = aList;
    >
    > ?
    >
    >> }
    >>
    >> void getList( std::vector<A>* v )
    >> {
    >> std::copy( aList.begin(), aList.end(), v->begin() );
    >>
    >> }

    >
    > I recently started a thread on that subject (whether "out" parameters
    > should be pointers instead of references):
    >
    > http://groups.google.com/group/comp.lang.c /browse_thread/thread/697f5fbff47a94e3#
    >
    > It seems most agreed that it's a dumb guideline.
    >


    I don't think it's a /dumb/ guideline. I was thinking in those guideline
    terms myself before. I thought that it would be easy to see whether a
    variable would be altered if providing the address of it. E.g.

    fnc( &myVar );

    would give a hint of that myVar is going to be modified. However, if you
    provide something that already is a pointer it would look like this.

    fnc( myVar );

    And therefore such guideline could be misleading.


    >> // Returning a reference to aList.
    >> const std::vector<A>& getList() { return aList; }

    >
    > That's the preffered way if the object being returned is a member of a
    > class (which means that the method is just a simple accessor
    > (getter)). More generally, it's ok as long as the object's lifetime is
    > well-defined and known to the caller (in the case of a member
    > variable, the lifetime is the same as that of its containing object).
    >
    >> const std::vector<A>::const_iterator& getList()
    >> {
    >> return aList.begin();
    >>
    >> }

    >
    > Seems pointless.
    >
    >> Do you know more ways to return a list? What's your preferred way to
    >> return a list of items?

    >
    > Either "vector<A> getList()" or "void getList(vector<A>&)" if I need
    > copying, or "const vector<A>& getList() const" (and possibly a non-
    > const overload) if the returned object is a member variable.


    Sometimes one doesn't need to copy but to return a newly created
    container. E.g.

    std::vector<std::string> getVector()
    {
    std::vector<std::string> hwVector;
    hwVector.push_back( "Hello World" );
    return hwVector;
    }

    I wonder how the new rvalue reference will be used with return values.
    Like this?

    std::vector<std::string>&& getVector()
    {
    std::vector<std::string> hwVector;
    hwVector.push_back( "Hello World" );
    return std::move( hwVector );
    }

    Do you know?
    DeMarcus, May 12, 2010
    #10
  11. DeMarcus

    James Kanze Guest

    On May 12, 9:18 am, DeMarcus <> wrote:

    > Here are a couple of ways to return some list of items.


    > struct A
    > {
    > };


    > std::vector<A> aList; // Some list of items.


    > // Returning a copy.
    > std::vector<A> getList() { return aList; }


    That's generally the preferred way. Until the profiler says
    otherwise.

    > void getList( std::vector<A>& v )
    > {
    > std::copy( aList.begin(), aList.end(), v.begin() );
    > }


    That should be:

    std::copy( aList.begin(), aList.end(), std::back_inserter(v) );

    > void getList( std::vector<A>* v )
    > {
    > std::copy( aList.begin(), aList.end(), v->begin() );
    > }


    Same thing here. You should be using sd::back_inserter(*v),
    rather than v->begin().

    Whether you use a pointer or a reference in this case depends on
    the local coding conventions.

    > // Returning a reference to aList.
    > const std::vector<A>& getList() { return aList; }


    Where does aList live? The semantics here are distinctly
    different from those of the previous versions, and the choice
    between this version and one of the previous should be made
    according to the desired semantics.

    > const std::vector<A>::const_iterator& getList()
    > {
    > return aList.begin();
    > }


    This simply doesn't work. You're returning a reference to a
    temporary.

    > Do you know more ways to return a list? What's your preferred
    > way to return a list of items?


    The only way to "return" a list is to return it.

    > Also, here comes another trickier one. Let's say I have a map
    > instead and want to return the keys.


    > std::map<std::string, A> aMap;


    > // Returning a copy of the keys.
    > std::vector<std::string> getList()
    > {
    > std::vector<std::string> aKeys;
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > aKeys.push_back( (*i).first );
    > return aKeys;
    > }


    > void getList( std::vector<std::string>& v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v.push_back( (*i).first );
    > }


    > void getList( std::vector<std::string>* v )
    > {
    > auto keysEnd = aMap.end();
    > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > v->push_back( (*i).first );
    > }


    > // But is it even possible to return a reference to // the
    > keys in a map?


    It's possible to return a reference to a single key, but it's
    not possible to return a reference to some collection which
    doesn't exist otherwise.

    > const std::vector<std::string>& getList() { /* What here? */ }


    > const std::vector<std::string>::const_iterator& getList()
    > {
    > /* What here? */
    > }


    > How do you usually deal with these kind of list returns?


    I return what I should return, until the profiler says
    otherwise. In which case, I use an out argument, whose format
    (reference or pointer) depends on the local coding conventions.

    --
    James Kanze
    James Kanze, May 12, 2010
    #11
  12. DeMarcus

    James Kanze Guest

    On May 12, 9:40 am, Kai-Uwe Bux <> wrote:
    > DeMarcus wrote:


    > > Here are a couple of ways to return some list of items.


    > > struct A
    > > {
    > > };


    > > std::vector<A> aList; // Some list of items.


    > > // Returning a copy.
    > > std::vector<A> getList() { return aList; }


    > > void getList( std::vector<A>& v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v.begin() );
    > > }


    > > void getList( std::vector<A>* v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v->begin() );
    > > }


    > > // Returning a reference to aList.
    > > const std::vector<A>& getList() { return aList; }


    > > const std::vector<A>::const_iterator& getList()
    > > {
    > > return aList.begin();
    > > }


    > > Do you know more ways to return a list? What's your
    > > preferred way to return a list of items?


    > I often use output iterators. So, my function signature looks
    > as follows:


    > template < typename OutIter >
    > OutIter get_items ( OutIter where, other args );


    Which means you're using a template. Which would be nice if
    templates really worked, but as they are currently implemented
    in most compilers, they require putting the implementation of
    the function in the header. Which means that they can't really
    be used unless the function is absolutely trivial and never
    changes.

    > That way, the client can decide which data structure should be
    > used when the items are to be stored.


    At a price of unacceptable coupling. This is an excellent
    solution for ultra-stable basic library code (e.g. like the
    standard library), but simply doesn't work at higher levels.

    --
    James Kanze
    James Kanze, May 12, 2010
    #12
  13. DeMarcus

    James Kanze Guest

    On May 12, 11:40 am, "Alf P. Steinbach" <> wrote:
    > On 12.05.2010 10:18, * DeMarcus:
    > > Here are a couple of ways to return some list of items.


    > > struct A
    > > {
    > > };


    > > std::vector<A> aList; // Some list of items.


    > > // Returning a copy.
    > > std::vector<A> getList() { return aList; }


    > This one is OK, and will be efficient with modern compiler.


    That depends on the context and the compiler. I've found that
    in many contexts, if the vector is large, it's not efficient
    with g++ or VC++ (or Sun CC). But if you can use better
    compilers, maybe.

    Anyway, this is clearly the preferred solution until the
    profiler says otherwise.

    > > void getList( std::vector<A>& v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v.begin() );
    > > }


    > This one's signature is OK as an opt-in alternative to the
    > first one (i.e. provide /both/, or just the first one).


    > However, the implementation is incorrect unless you assume
    > that the argument is of exactly the right size for the result
    > (and that assumption would be unrealistic, to put it mildly).


    > You could write it like


    > void getList( std::vector< A >& v )
    > {
    > std::vector< A >( aList.begin(), aList.end() ).swap( v );
    > }


    Or simply use clear and a back_inserter. Or resize the target
    first. The optimal solution will depend on context.

    > > void getList( std::vector<A>* v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v->begin() );
    > > }


    > This one is just bad. Why would you want to support
    > nullpointer argument? If someone calls 'getList' it's in order
    > to get that list, not in order to do nothing.


    The choice depends on the local coding conventions.

    > Anyway, under normal assumptions the implementation is incorrect.


    > > // Returning a reference to aList.
    > > const std::vector<A>& getList() { return aList; }


    > This one's OK if you're clear on what it does.


    It's OK if you actually have an aList somewhere, and you want to
    return it.

    > > const std::vector<A>::const_iterator& getList()
    > > {
    > > return aList.begin();
    > > }


    > This is one is just silly, the caller can't do anything
    > reasonable with the returned iterator.


    > > Do you know more ways to return a list?


    > How about ways to return lists, instead of vectors (arrays)?


    > > What's your preferred way to return a list of items?


    > That doesn't make sense without a lot more explanation of
    > exactly what you mean by "list" and in what context you'd want
    > to return -- what?


    Yes and no. The "preferred" way of returning something
    (anything, including a list of whatever) is to return it. You
    only vary from that when the profiler says you must. In which
    case, you have the context, and you adopt the solution most
    suited to the context.

    > > Also, here comes another trickier one. Let's say I have a
    > > map instead and want to return the keys.


    > > std::map<std::string, A> aMap;


    > > // Returning a copy of the keys.
    > > std::vector<std::string> getList()
    > > {
    > > std::vector<std::string> aKeys;
    > > auto keysEnd = aMap.end();
    > > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > > aKeys.push_back( (*i).first );
    > > return aKeys;
    > > }


    > > void getList( std::vector<std::string>& v )
    > > {
    > > auto keysEnd = aMap.end();
    > > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > > v.push_back( (*i).first );
    > > }


    > > void getList( std::vector<std::string>* v )
    > > {
    > > auto keysEnd = aMap.end();
    > > for( auto i = aMap.begin(); i != keysEnd; ++i )
    > > v->push_back( (*i).first );
    > > }


    > > // But is it even possible to return a reference to
    > > // the keys in a map?


    > > const std::vector<std::string>& getList() { /* What here? */ }


    > > const std::vector<std::string>::const_iterator& getList()
    > > {
    > > /* What here? */
    > > }


    > How about defining an iterator that walks through the keys.
    > Then you don't have to create all those string objects.


    A transforming iterator. Boost has some good code which will
    allow you to do this very simply. Of course, you'll need two
    functions: listBegin and listEnd, rather than just one, but this
    does allow the most freedom for the user.

    --
    James Kanze
    James Kanze, May 12, 2010
    #13
  14. DeMarcus

    James Kanze Guest

    On May 12, 2:21 pm, Sousuke <> wrote:
    > On May 12, 3:18 am, DeMarcus <> wrote:


    [...]
    > > // Returning a copy.
    > > std::vector<A> getList() { return aList; }


    > > void getList( std::vector<A>& v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v.begin() );


    > Isn't that just a more complicated and unsafe way of doing:


    > v = aList;


    > ?


    The two don't have the same semantics. At all.

    > > }


    > > void getList( std::vector<A>* v )
    > > {
    > > std::copy( aList.begin(), aList.end(), v->begin() );
    > > }


    > I recently started a thread on that subject (whether "out"
    > parameters should be pointers instead of references):


    > http://groups.google.com/group/comp.lang.c /browse_thread/thread/697...


    > It seems most agreed that it's a dumb guideline.


    I don't see where you got that. It's an arbitrary guideline, in
    the sense that there is no right answer. Different companies
    will use different guidelines---there are pros and cons for
    each.

    [...]
    > > Do you know more ways to return a list? What's your preferred way to
    > > return a list of items?


    > Either "vector<A> getList()" or "void getList(vector<A>&)" if I need
    > copying, or "const vector<A>& getList() const" (and possibly a non-
    > const overload) if the returned object is a member variable.


    The only "clean" solution is "vector<A> getList()".
    Regretfully, it can have significant overhead if the list
    contains a lot of elements, and the function is called in a
    tight loop. In which case, you choose among a number of other
    solutions, depending on the context and the local coding
    guidelines.

    --
    James Kanze
    James Kanze, May 12, 2010
    #14
  15. DeMarcus

    James Kanze Guest

    On May 12, 3:07 pm, DeMarcus <> wrote:
    > Sousuke wrote:


    [...]
    > > I recently started a thread on that subject (whether "out"
    > > parameters should be pointers instead of references):


    > >http://groups.google.com/group/comp.lang.c /browse_thread/thread/697...


    > > It seems most agreed that it's a dumb guideline.


    > I don't think it's a /dumb/ guideline.


    Certainly not. It's an arbitrary guideline, in the sense that
    there are no killer arguments for any of the alternatives.
    There are several reasonable choices (including this one).

    > I was thinking in those guideline terms myself before. I
    > thought that it would be easy to see whether a variable would
    > be altered if providing the address of it.


    I sort of prefer it too. But not to the point of saying that
    the other choices are dumb. The only "dumb" decision here is
    not recognizing that several options are equally valid, and that
    your choice is more or less arbitrary.

    > E.g.


    > fnc( &myVar );


    > would give a hint of that myVar is going to be modified.
    > However, if you provide something that already is a pointer it
    > would look like this.


    > fnc( myVar );


    > And therefore such guideline could be misleading.


    Yes and no. Presumably, you know what you're passing.
    (Presumably, aussi, the function name would indicate what it
    does, so you'd know what it modifies. Except, of course, that
    in some numerics work, and probably in other domains as well,
    you might have two or three out parameters.)

    --
    James Kanze
    James Kanze, May 12, 2010
    #15
  16. DeMarcus

    Ian Collins Guest

    On 05/13/10 10:30 AM, James Kanze wrote:
    > On May 12, 9:40 am, Kai-Uwe Bux<> wrote:
    >> DeMarcus wrote:


    <snip>

    >>> Do you know more ways to return a list? What's your
    >>> preferred way to return a list of items?

    >
    >> I often use output iterators. So, my function signature looks
    >> as follows:

    >
    >> template< typename OutIter>
    >> OutIter get_items ( OutIter where, other args );

    >
    > Which means you're using a template. Which would be nice if
    > templates really worked, but as they are currently implemented
    > in most compilers, they require putting the implementation of
    > the function in the header. Which means that they can't really
    > be used unless the function is absolutely trivial and never
    > changes.


    Oh come on James, that's going a bit too far. What really matters in
    practice is how long you have to wait for a build. If that becomes too
    big a deal, throw more hardware at it.

    --
    Ian Collins
    Ian Collins, May 12, 2010
    #16
  17. DeMarcus

    Kai-Uwe Bux Guest

    Ian Collins wrote:

    > On 05/13/10 10:30 AM, James Kanze wrote:
    >> On May 12, 9:40 am, Kai-Uwe Bux<> wrote:
    >>> DeMarcus wrote:

    >
    > <snip>
    >
    >>>> Do you know more ways to return a list? What's your
    >>>> preferred way to return a list of items?

    >>
    >>> I often use output iterators. So, my function signature looks
    >>> as follows:

    >>
    >>> template< typename OutIter>
    >>> OutIter get_items ( OutIter where, other args );

    >>
    >> Which means you're using a template. Which would be nice if
    >> templates really worked, but as they are currently implemented
    >> in most compilers, they require putting the implementation of
    >> the function in the header. Which means that they can't really
    >> be used unless the function is absolutely trivial and never
    >> changes.

    >
    > Oh come on James, that's going a bit too far. What really matters in
    > practice is how long you have to wait for a build. If that becomes too
    > big a deal, throw more hardware at it.


    Well, I understand that there are shops where templates are prohibited by
    local coding guidelines. I would suppose they have those rules in place for
    good reasons. Admittedly, under those circumstances, using the OutIter
    signature is not feasible.

    I would, however, maintain that templates _should_ be fine for many
    projects. I do see that they interact poorly with the C++ model of separate
    compilation and source code file inclusion: taken together, the package does
    not really scale all that well. I am just not certain at which point scaling
    becomes a valid reason to ban templates.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, May 13, 2010
    #17
  18. DeMarcus

    Jorgen Grahn Guest

    On Wed, 2010-05-12, DeMarcus wrote:
    > Alf P. Steinbach wrote:

    ....
    >> You could write it like
    >>
    >> void getList( std::vector< A >& v )
    >> {
    >> std::vector< A >( aList.begin(), aList.end() ).swap( v );
    >> }
    >>

    >
    > That's nice! Where do I find tricks like that? I don't find such things
    > in Josuttis' book.


    It's "just" a fancy way of saying:

    std::vector< A > tmp( aList.begin(), aList.end() );
    tmp.swap( v );

    I hope every half-decent book stresses the importance of swapping, and
    clearly shows how all the standard containers can be constructed from
    any kind of suitable iterator.

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
    Jorgen Grahn, May 13, 2010
    #18
  19. On 13.05.2010 00:40, * James Kanze:
    > On May 12, 11:40 am, "Alf P. Steinbach"<> wrote:
    >> On 12.05.2010 10:18, * DeMarcus:
    >>> Here are a couple of ways to return some list of items.

    >
    >>> struct A
    >>> {
    >>> };

    >
    >>> std::vector<A> aList; // Some list of items.

    >
    >>> // Returning a copy.
    >>> std::vector<A> getList() { return aList; }

    >
    >> This one is OK, and will be efficient with modern compiler.

    >
    > That depends on the context and the compiler. I've found that
    > in many contexts, if the vector is large, it's not efficient
    > with g++ or VC++ (or Sun CC).


    Huh, that's news to me.

    I'm pretty skeptical about that claim since both g++ and MSVC do RVO
    optimization by default, but I'll try to remember to check this.

    If you're talking about comparing it with a situation where you can avoid
    reallocation of the vector's buffer then that doesn't depend on the compiler.


    > But if you can use better
    > compilers, maybe.
    >
    > Anyway, this is clearly the preferred solution until the
    > profiler says otherwise.


    Yah, agreed.


    >>> void getList( std::vector<A>& v )
    >>> {
    >>> std::copy( aList.begin(), aList.end(), v.begin() );
    >>> }

    >
    >> This one's signature is OK as an opt-in alternative to the
    >> first one (i.e. provide /both/, or just the first one).

    >
    >> However, the implementation is incorrect unless you assume
    >> that the argument is of exactly the right size for the result
    >> (and that assumption would be unrealistic, to put it mildly).

    >
    >> You could write it like

    >
    >> void getList( std::vector< A>& v )
    >> {
    >> std::vector< A>( aList.begin(), aList.end() ).swap( v );
    >> }

    >
    > Or simply use clear and a back_inserter. Or resize the target
    > first. The optimal solution will depend on context.


    I like this way as a "default" for this function signature because it guarantees
    to get rid of the old buffer allocation (so that one does not hang on to the
    largest buffer size forever), and because it's simplest.


    >>> void getList( std::vector<A>* v )
    >>> {
    >>> std::copy( aList.begin(), aList.end(), v->begin() );
    >>> }

    >
    >> This one is just bad. Why would you want to support
    >> nullpointer argument? If someone calls 'getList' it's in order
    >> to get that list, not in order to do nothing.

    >
    > The choice depends on the local coding conventions.


    Yes, but one simply shouldn't work for Google as a C++ programmer. :)


    >> Anyway, under normal assumptions the implementation is incorrect.

    >
    >>> // Returning a reference to aList.
    >>> const std::vector<A>& getList() { return aList; }

    >
    >> This one's OK if you're clear on what it does.

    >
    > It's OK if you actually have an aList somewhere, and you want to
    > return it.


    I think you mean, if the lifetime of 'aList' is sufficient. In the OP's example
    it is.


    >>> const std::vector<A>::const_iterator& getList()
    >>> {
    >>> return aList.begin();
    >>> }

    >
    >> This is one is just silly, the caller can't do anything
    >> reasonable with the returned iterator.

    >
    >>> Do you know more ways to return a list?

    >
    >> How about ways to return lists, instead of vectors (arrays)?

    >
    >>> What's your preferred way to return a list of items?

    >
    >> That doesn't make sense without a lot more explanation of
    >> exactly what you mean by "list" and in what context you'd want
    >> to return -- what?

    >
    > Yes and no. The "preferred" way of returning something
    > (anything, including a list of whatever) is to return it. You
    > only vary from that when the profiler says you must. In which
    > case, you have the context, and you adopt the solution most
    > suited to the context.


    This seems to conflate two different meanings of "return". For example, if you
    have a pointer p you might return *p, what's "it" that's being returned? So as I
    wrote, in order to answer the OP's question it would need to more details.


    >>> Also, here comes another trickier one. Let's say I have a
    >>> map instead and want to return the keys.

    >
    >>> std::map<std::string, A> aMap;

    >
    >>> // Returning a copy of the keys.
    >>> std::vector<std::string> getList()
    >>> {
    >>> std::vector<std::string> aKeys;
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> aKeys.push_back( (*i).first );
    >>> return aKeys;
    >>> }

    >
    >>> void getList( std::vector<std::string>& v )
    >>> {
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> v.push_back( (*i).first );
    >>> }

    >
    >>> void getList( std::vector<std::string>* v )
    >>> {
    >>> auto keysEnd = aMap.end();
    >>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>> v->push_back( (*i).first );
    >>> }

    >
    >>> // But is it even possible to return a reference to
    >>> // the keys in a map?

    >
    >>> const std::vector<std::string>& getList() { /* What here? */ }

    >
    >>> const std::vector<std::string>::const_iterator& getList()
    >>> {
    >>> /* What here? */
    >>> }

    >
    >> How about defining an iterator that walks through the keys.
    >> Then you don't have to create all those string objects.

    >
    > A transforming iterator. Boost has some good code which will
    > allow you to do this very simply. Of course, you'll need two
    > functions: listBegin and listEnd, rather than just one, but this
    > does allow the most freedom for the user.


    I didn't know about the Boost adaptors, I'll look into it (later); thanks!


    Cheers,

    - Alf

    --
    blog at <url: http://alfps.wordpress.com>
    Alf P. Steinbach, May 13, 2010
    #19
  20. DeMarcus

    Jeff Flinn Guest

    DeMarcus wrote:
    > Jeff Flinn wrote:
    >> DeMarcus wrote:
    >>> Öö Tiib wrote:
    >>>> On May 12, 11:18 am, DeMarcus <> wrote:
    >>>>> Hi,
    >>>>>
    >>>>> Here are a couple of ways to return some list of items.
    >>>>>
    >>>>> struct A
    >>>>> {
    >>>>>
    >>>>> };
    >>>>>
    >>>>> std::vector<A> aList; // Some list of items.
    >>>>>
    >>>>> // Returning a copy.
    >>>>> std::vector<A> getList() { return aList; }
    >>>>>
    >>>>> void getList( std::vector<A>& v )
    >>>>> {
    >>>>> std::copy( aList.begin(), aList.end(), v.begin() );
    >>>>>
    >>>>> }
    >>>>>
    >>>>> void getList( std::vector<A>* v )
    >>>>> {
    >>>>> std::copy( aList.begin(), aList.end(), v->begin() );
    >>>>>
    >>>>> }
    >>>>>
    >>>>> // Returning a reference to aList.
    >>>>> const std::vector<A>& getList() { return aList; }
    >>>>>
    >>>>> const std::vector<A>::const_iterator& getList()
    >>>>> {
    >>>>> return aList.begin();
    >>>>>
    >>>>> }
    >>>>>
    >>>>> Do you know more ways to return a list? What's your preferred way to
    >>>>> return a list of items?
    >>>>>
    >>>>> Also, here comes another trickier one. Let's say I have a map instead
    >>>>> and want to return the keys.
    >>>>>
    >>>>> std::map<std::string, A> aMap;
    >>>>>
    >>>>> // Returning a copy of the keys.
    >>>>> std::vector<std::string> getList()
    >>>>> {
    >>>>> std::vector<std::string> aKeys;
    >>>>> auto keysEnd = aMap.end();
    >>>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>>> aKeys.push_back( (*i).first );
    >>>>> return aKeys;
    >>>>>
    >>>>> }
    >>>>>
    >>>>> void getList( std::vector<std::string>& v )
    >>>>> {
    >>>>> auto keysEnd = aMap.end();
    >>>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>>> v.push_back( (*i).first );
    >>>>>
    >>>>> }
    >>>>>
    >>>>> void getList( std::vector<std::string>* v )
    >>>>> {
    >>>>> auto keysEnd = aMap.end();
    >>>>> for( auto i = aMap.begin(); i != keysEnd; ++i )
    >>>>> v->push_back( (*i).first );
    >>>>>
    >>>>> }
    >>>>>
    >>>>> // But is it even possible to return a reference to
    >>>>> // the keys in a map?
    >>>>>
    >>>>> const std::vector<std::string>& getList() { /* What here? */ }
    >>>>>
    >>>>> const std::vector<std::string>::const_iterator& getList()
    >>>>> {
    >>>>> /* What here? */
    >>>>>
    >>>>> }
    >>>>>
    >>>>> How do you usually deal with these kind of list returns?
    >>>>
    >>>> Usually...
    >>>>
    >>>> I avoid writing functions that are getters, copiers or even worse ...
    >>>> setters, because these indicate lousy design. I usually try my best to
    >>>> have interface that allows operations that make sense to do with the
    >>>> objects of given type and not interface that allows mechanical
    >>>> setting, getting and copying of the properties of objects.
    >>>>
    >>>
    >>> Ok, great. Actually I'm also very considered with clean design, but
    >>> sometimes I find it impossible to do anything else than returning a
    >>> container.
    >>>
    >>> I'm playing around with a command in Linux called backtrace_symbols.
    >>> The command gives you the stack trace. Now I want to wrap that
    >>> somehow and this is what I've made so far.
    >>>
    >>> std::vector<std::string> getStackTrace();
    >>>
    >>> How would you do this? Like this
    >>>
    >>> std::vector<std::string> stackTrace();
    >>>
    >>> or provide functions that can be applied to the stack trace, e.g.
    >>>
    >>> std::eek:stream& operator<<( std::eek:stream&, const StackTrace& );

    >>
    >> Your implication here of a StackTrace class would be my choice. Along
    >> with StackTraceItem class and whatever other classes embody the domain
    >> entities. Then as you've shown each of these classes could be
    >> streamable. The StackTrace class could then provide a container
    >> interface including the expected typedefs, iterators and methods.
    >>
    >> Jeff
    >>

    >
    > I agree with you that one should not be afraid of making classes of even
    > the simplest things. But sometimes I just feel to be lazy, and in this
    > case the stack trace is just a list of text, so just to get up running
    > with a decent solution I chose to just provide a container.


    Aah, but if you do anything with that text other than simply write it
    out verbatim, you've got behavior leaking all over your application when
    you process the item. By decomposing at this point I always end up with
    some abastractions that I can reuse in multiple places.

    I would even start looking at where the data for this vector is coming
    from, which is probably some stream, then I'd develop the grammar to
    parse that data directly into domain entities. This always ends up using
    less memory, fewer cycles and is more flexible with less coupling.

    > Then came my mind block; I always return something like
    > std::vector<std::string>, but is that the best way to return a
    > container? How are containers returned with the new C++0x rvalue
    > reference for instance?


    IIRC, rvalue refs doesn't change what or how you return an unnamed
    object from a function, but does provide a way for consumers to avoid
    copies by providing a means to overload on another type and in the case
    of vector to only swap it's internal data pointer rather than copy all
    items.

    Jeff
    Jeff Flinn, May 13, 2010
    #20
    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.
Similar Threads
  1. Rod

    Preferred way of passing data

    Rod, Aug 25, 2004, in forum: ASP .Net
    Replies:
    5
    Views:
    1,575
    Anon-E-Moose
    Aug 26, 2004
  2. H5N1
    Replies:
    1
    Views:
    742
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Apr 12, 2006
  3. Mike Campo

    Your preferred books

    Mike Campo, Dec 10, 2003, in forum: C++
    Replies:
    1
    Views:
    303
    jeffc
    Dec 10, 2003
  4. Mike Campo

    Your preferred books

    Mike Campo, Dec 10, 2003, in forum: C++
    Replies:
    2
    Views:
    413
    Christoph Rabel
    Dec 10, 2003
  5. Anjan Bhowmik
    Replies:
    1
    Views:
    467
    Misbah Arefin
    Feb 14, 2008
Loading...

Share This Page