How could I copy Obj*[] into std::list<Obj*> in C++?

Answered How could I copy Obj*[] into std::list<Obj*> in C++?

  • Thursday, December 06, 2012 8:45 AM
     
     

    Hi,

    I would like to copy the elements in a array into std::list the thing is that the array has pointers to the elements... which is the best way to do it? could you please post an example?

    thanks

    • Moved by LeoTang Friday, December 07, 2012 9:00 AM (From:Windows Communication Foundation (WCF))
    •  

All Replies

  • Friday, December 07, 2012 9:53 AM
     
     Answered Has Code

    On 06/12/2012 09:45, masuberu wrote:


    I would like to copy the elements in a array into std::list the thing is that the array has pointers to the elements... which is the best way to do it? could you please post an example?

    There are some points you may want to clarify.

    For example: are those raw pointers? Who owns the pointed objects?
    If these are raw pointers and they are just "observing" pointers, then it is OK to use them in STL containers (assuming that the pointed-to objects outlive those observing pointers).

    But if these are owning pointers, then you may want to use smart pointers like std::unique_ptr in C++11 or shared_ptr in C++98/03 (or std::shared_ptr also in C++11 if you have a shared ownership semantics).

    In any case, if you have a raw pointers Obj* array allocated on the stack, you can use a proper std::list constructor overload to initialize the list of raw pointers from the array:

    // rawArray is an array of Obj* allocated on the stack
    std::list<Obj *> myList(rawArray, rawArray + _countof(rawArray));
    

    A compilable code sample follows:

    #include <stdlib.h>     // for _countof()
    
    #include <iostream>     // for std::cout
    #include <list>         // for std::list
    #include <sstream>      // for std::ostringstream
    #include <string>       // for std::string
    
    using namespace std;
    
    
    // Test class
    class X 
    {
    public:    
        explicit X(int n) 
            : m_n(n) 
        {
            cout << Name() << " created.\n";
        }
        
        
        ~X()
        {
            cout << Name() << " destroyed.\n";
        }
    
    
        string Name() const
        {
            ostringstream os;
            os << "X(" << m_n << ")";
            return os.str();
        }
    
        
    private:
        int m_n;   
    };
    
    
    // Test
    int main()
    {
        // Array of raw pointers
        typedef X* XPtr;
        
        // Dynamically allocate some objects
        XPtr v[3];
        v[0] = new X(10);
        v[1] = new X(20);
        v[2] = new X(30);
        
        // Build a list of observing pointers from raw array of pointers
        list<X*> l(v, v + _countof(v));
    
        // Print list content
        cout << "\nList contains:\n";
        for (auto it = l.begin(); it != l.end(); ++it)
            cout << (*it)->Name() << endl;       
        cout << '\n';
               
        // Release the allocated objects
        for (int i = 0; i < _countof(v); i++)
        {
            delete v[i];
        }        
    }
    

    Giovanni


  • Friday, December 07, 2012 10:48 PM
     
      Has Code

    Thanks to new (C++11) std::begin and std::end it's pretty easy :-)

    Here's the relevant code snippet:

    #include <iterator>     // for std::begin, std::end
    . . .
    list<X*> l(std::begin(v), std::end(v));

    That's it! :-)
    Here's complete source code (for ease of comparison based on Giovanni's):
    http://www.stacked-crooked.com/view?id=0efc1ed4a92b4156bb2c9f30739ffbce

    More info:
    std::begin - http://en.cppreference.com/w/cpp/iterator/begin
    std::end - http://en.cppreference.com/w/cpp/iterator/end

    Alternative solution (useful, for example, when you already have a list) is to use std::copy (note, we can also use std::distance to get the element's count, no reason/need to use non-standard/non-portable/not-recommended "_countof").

    Code snippet:

    #include <algorithm>    // for std::copy
    #include <iterator>     // for std::begin, std::end, std::distance
    . . .
    auto count = std::distance(std::begin(v), std::end(v));
    list<X*> l(count);
    std::copy(std::begin(v), std::end(v), std::begin(l));
    

    More info:
    - std::distance - http://en.cppreference.com/w/cpp/iterator/distance
    - std::copy - http://en.cppreference.com/w/cpp/algorithm/copy

    Complete source code:
    http://www.stacked-crooked.com/view?id=78c76bce08eaf3dfde016f1c281019ba



    • Edited by MattPD Friday, December 07, 2012 10:50 PM
    •  
  • Sunday, December 09, 2012 8:07 PM
     
      Has Code

    Just a small note on the use of _countof. Since this is a Microsoft MSDN forum, I had in mind a Visual Studio specific solution.

    Moreover, frankly, I find much easier the form:

    _countof(v)

    than:

    std::distance(std::begin(v), std::end(v))

    to get the element count of a raw array.

    If there is no portable _countof(), then the standard guys may want to add it, considering the convenience.

    Giovanni

  • Monday, December 10, 2012 6:37 PM
     
      Has Code

    Giovanni: I see your point.

    At the same time, from the end-user's (here: programmer's) perspective you're really talking about an internal implementation detail, since what the user is going to see is just the variable name, "count". (Alternatively, you can wrap it inside a similarly-named inlined function).

    To be fair, I think the internal implementation of _countof is even messier (and more confusing):

    http://social.msdn.microsoft.com/Forums/en/vclanguage/thread/252b4be3-8adf-49e4-a240-93ccb91849f2

    So, if we're still talking about the internal implementation (say, for the ease of debugging), I'd much rather use the std::distance solution.

    On the other hand, if we're talking from the end-user's (here: programmer who's not debugging it at the moment, but just reusing the code) point of view, then the internal implementation is less important, and it's just the name that is visible and matters -- then, "count" is not really any harder to interpret than "_countof".

    ---

    EDIT: It turns out that your observation that it's sufficiently convenient feature that it should really be in the standard was correct! :-)

    It exists in C++11 and it's called std::extent. So now, we have one more alternative:

    auto count = std::extent<decltype(v)>::value;

    More: http://stackoverflow.com/a/13747781 // a "countof" wrapper makes the syntax shorter.

    Complete source code: http://www.stacked-crooked.com/view?id=44e21dfc2bfa04e0ac6ea2bb6486d160

    For multidimensional arrays, std::rank may also come in handy.

    So, thanks -- that was a good point!




    • Edited by MattPD Monday, December 10, 2012 6:51 PM
    •