Thread: Yet another array question...

  1. #1
    Registered User
    Join Date
    Nov 2005
    Posts
    673

    Yet another array question...

    I made another class. I know there is a similar class in boost, but it is very touchy on syntax. This one I hope is a little better than my other, but I thought have a smart pointer class for array's would be kinda cool.

    so here it is, and hopefully you guys catch what I have not ( which is very likely )
    Code:
    namespace Varia
    {
        template<typename T>
        void Free(T*& p_Obj)
        {
            delete p_Obj; p_Obj = 0;
        }
    
        template<typename T>
        void FreeArray(T*& p_Obj)
        {
            delete [] p_Obj; p_Obj = 0;
        }
    
        template<typename T>
        class Array
        {
        private:
            T* m_Array;
            unsigned m_Size;
    
        public:
            Array()
                :m_Array(0), m_Size(0)
            {
            }
    
            Array(unsigned p_Size)
                :m_Array(0), m_Size(p_Size)
            {
                if  ( m_Size > 0 )
                    m_Array = new T[m_Size];
            }
    
            Array(const Array& p_Copy)
                :m_Array(0), m_Size(0)
            {
                Copy(p_Copy);
            }
    
            const Array& operator=(const Array& p_Copy)
            {
                Copy(p_Copy); return *this;
            }
    
            void Realloc(unsigned p_Size)
            {
                T* TempArray = 0;
                if ( p_Size+1 < 1 )
                    return;
                TempArray = new T[p_Size+1];
                for ( unsigned x = 0; x < p_Size+1 && x < m_Size; ++x )
                {
                    TempArray[x] = m_Array[x];
                }
                Release();
                m_Array = TempArray;
                m_Size = p_Size+1;
            }
    
            void Release()
            {
                FreeArray(m_Array);
            }
    
            T& operator[](unsigned p_Index)
            {
                if ( p_Index >= m_Size )
                {
                    Realloc(p_Index);
                }
                return m_Array[p_Index];
            }
    
            const T& operator[](unsigned p_Index) const
            {
                if ( p_Index >= m_Size)
                {
                    Realloc(p_Index);
                }
                return m_Array[p_Index];
            }
    
        private:
            void Copy(const Array& p_Copy)
            {
                if ( &p_Copy == this )
                    return;
                T* TempArray = 0;
                if ( p_Copy.m_Size > 0 )
                {
                    TempArray = new T[p_Copy.m_Size];
                    for ( unsigned x = 0; x < p_Copy.m_Size; ++x )
                    {
                        TempArray[x] = p_Copy.m_Array[x];
                    }
                }
                Release();
                m_Array = TempArray;
                m_Size = p_Copy.m_Size;
            }
        };
    }
    Any input is greatly appreciated.

    - Main purpose, I am getting tired of forgetting to clean up dynamic memory.

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    The fact that the const version of your subscript operator does memory allocation sometimes seems to be an oversight. That operation changes the object (even if the compiler disagrees with me). Allocation should probably happen somewhere else a la resize or push_back, but never the less you have a problem with const correctness.

  3. #3
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    How would I fix that if the subscript operator is supposed to always insure that the index is not out of bounds?

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,613
    The typical response to out of bounds access is throwing an exception or making an assertion.
    Code:
    const Contained & Array::operator [] ( std::ptrdiff_t i ) const
    {
      if ( i >= m_Size ) {
        throw std::out_of_range( "can't happen\n" );
      }
      return m_Array[i];
    }
    Last edited by whiteflags; 11-12-2008 at 11:25 PM. Reason: Example added

  5. #5
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I was trying to stay away from the typical way. I am not trying to re-create std::vector, or any other STL containers.

    I guess I could just get rid of the const operator[], and have the value be copied during every access. As I doubt that the const operator even gets called in very many circumstances.

  6. #6
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Quote Originally Posted by Raigne View Post
    I was trying to stay away from the typical way. I am not trying to re-create std::vector, or any other STL containers.
    Staying away from the typical way basically means making something worse. Like it or not your current implementation is already going to throw an exception if you try and access an item at say 0xFFFFFFFF due to it failing to allocate memory. Yet if you only go a little over the end it wont throw. (assuming you put in the required const_casts, entering the land of undefined behaviour in the process since you violate the constness)
    Just be consistent and throw or assert, in both cases

    I guess I could just get rid of the const operator[], and have the value be copied during every access. As I doubt that the const operator even gets called in very many circumstances.
    That all depends on how sloppy you've been with const correctness in the rest of your program. In well written code, the const version could very well be called much more than the non-const version.
    You have to change something anyway because you can't call a non-const member function from a const member function.

    What, no member function for querying the size?
    And aren't you missing something rather important, say a destructor!

    Those of us who care about efficiency would complain about the lack of a no-throw std::swap specialisation. Try sorting a vector of these classes and you'll notice the huge difference!

    You've also lucked out of making it exception safe. If the assignment operator of T throws, you've leaked, during Copy or Realloc.

    I'd give it a 5.5 out of 10, considering the destructor is missing.
    You should read the Guru of the Week articles from Herb Sutter
    Last edited by iMalc; 11-13-2008 at 12:16 AM.
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  7. #7
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    I guess I will use the typical approach.

    I just ran a few tests using the hi-resolution timer in Win32.

    If the data is pre-allocated(reserved), then assignment of 100,000 integers takes 357 ticks(approx. 35 milliseconds).
    If the same amount of integers are assigned without reserving then it takes around approx. 9 seconds.
    So, it is pretty apparent with is the better approach. Although I guess this should have been obvious to me from the start.

    I realize 100,000 is a little high for normal use, but I try to test rigorously.

    edit: destructor is in my code, but I must of forgot to hit ctrl-c again before posting.
    Last edited by Raigne; 11-13-2008 at 12:19 AM.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Raigne View Post
    - Main purpose, I am getting tired of forgetting to clean up dynamic memory.
    So why exactly aren't you using std::vector?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    The larch
    Join Date
    May 2006
    Posts
    3,573
    You might also time how long 100000 pushbacks to vector takes.

    With your original approach it seems that you would reallocate and copy everything each time you add a new item, something which vector for example doesn't do.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  10. #10
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by Raigne View Post
    I made another class. I know there is a similar class in boost, but it is very touchy on syntax. This one I hope is a little better than my other, but I thought have a smart pointer class for array's would be kinda cool.

    so here it is, and hopefully you guys catch what I have not ( which is very likely )

    Any input is greatly appreciated.

    - Main purpose, I am getting tired of forgetting to clean up dynamic memory.
    You could also take a look at my AutoPtr class or Elysia's class for some ideas:
    http://cboard.cprogramming.com/showt...hlight=AutoPtr
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  11. #11
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    ZOMG! That class is so old, and probably too bloated. If I rewrote that class, I could probably trim it to 10&#37; of its size.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  12. #12
    Registered User
    Join Date
    Nov 2005
    Posts
    673
    With vector the time with push_back() on 100000 is 86 milliseconds (approx.)
    My array is 8654 milliseconds (approx.)

    Using reserve vector is 8 milliseconds(approx.)
    My array is 3 milliseconds(approx.)

    So, my realloc isn't right, but with the reserved there is a little more speed with my array.

    I guess I will just give up on this for now, and stick with STL ( at least till I understand how they work a little better )

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Dynamic Mutli dimensional Array question.
    By fatdunky in forum C Programming
    Replies: 6
    Last Post: 02-22-2006, 07:07 PM
  2. Class Template Trouble
    By pliang in forum C++ Programming
    Replies: 4
    Last Post: 04-21-2005, 04:15 AM
  3. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  4. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  5. array question?
    By correlcj in forum C++ Programming
    Replies: 1
    Last Post: 11-08-2002, 06:27 PM