Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Template Class Pointer - Would like explanation for unexpected behavior

Template Class Pointer - Would like explanation for unexpected behavior

Scheduled Pinned Locked Moved C / C++ / MFC
asp-netdatabasewpfdata-structuresquestion
7 Posts 5 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    Foothill
    wrote on last edited by
    #1

    I am expanding my knowledge of class templates so I am building a very basic template of type Array<T>. I'll include only the code that pertains to the behavior that is confusing me. Template Header

    // MyArray.h

    #include #define CORE_ARRAY_DEFAULT_LENGTH 20

    template class Array
    {
    private:
    T** _array;
    int _size;
    int _length;

    public:
    Array(void)
    {
    _array = new T*[CORE_ARRAY_DEFAULT_LENGTH]();
    _size = CORE_ARRAY_DEFAULT_LENGTH;
    _length = 0;
    }
    ~Array(void) { Clear(); }

    int Size(void) const { return _size; }
    int Length(void) const { return _length; }

    T operator [] (int index) const
    {
    if ((index < 0) || (index >= _length))
    throw std::out_of_range("index");
    else
    return * _array[index];
    }

    void Add(T value)
    {
    if (_length == _size)
    Resize();

    _array[_length] = new T(value);
    ++_length;
    }

    /* Other functions follow CopyArray(), CloneArray(), Resize(), Clear(), InsertAt(), etc... */
    }

    And the source

    #include "MyArray.h"
    #include #include void main(void)
    {
    // This behaves as expected
    Array iArrayA;

    for (int i = 0; i < 10; ++i)
    iArrayA.Add(i);
    for (int i = 0; i < 10; ++i)
    printf("%d\n", iArrayA[i]);

    // But this was returning odd results
    Array * iArrayB = new Array();

    for (int i = 0; i < 10; ++i)
    iArrayB->Add(i); // confirmed that the values were stored correctly
    for (int i = 0; i < 10; ++i)
    printf("%d\n", iArrayB[i]; // outputs were not what I expected

    delete iArrayB;

    system("pause");
    }

    Here is what I had to change it to to get the desired results:

    printf("%d\n", iArrayB[0][i]);

    What I don't get here is why when the array was declared as a local (Array<int> iArrayA;) did the accessor [] pull the stored int at the correct element but when I had the array declared as a pointer on the heap (Array<int> * iArrayB = new iArray();) the accessor [] was seemingly pulling random data until I added the [0] before the [i]? I am wondering if this has something to do with overloading the array subscript operator. Which is what has jumped out at me while I am writing this. Also, is there a way I can code the accessor to work for both locals and heap pointers? Is there any way around this?

    L F V 3 Replies Last reply
    0
    • F Foothill

      I am expanding my knowledge of class templates so I am building a very basic template of type Array<T>. I'll include only the code that pertains to the behavior that is confusing me. Template Header

      // MyArray.h

      #include #define CORE_ARRAY_DEFAULT_LENGTH 20

      template class Array
      {
      private:
      T** _array;
      int _size;
      int _length;

      public:
      Array(void)
      {
      _array = new T*[CORE_ARRAY_DEFAULT_LENGTH]();
      _size = CORE_ARRAY_DEFAULT_LENGTH;
      _length = 0;
      }
      ~Array(void) { Clear(); }

      int Size(void) const { return _size; }
      int Length(void) const { return _length; }

      T operator [] (int index) const
      {
      if ((index < 0) || (index >= _length))
      throw std::out_of_range("index");
      else
      return * _array[index];
      }

      void Add(T value)
      {
      if (_length == _size)
      Resize();

      _array[_length] = new T(value);
      ++_length;
      }

      /* Other functions follow CopyArray(), CloneArray(), Resize(), Clear(), InsertAt(), etc... */
      }

      And the source

      #include "MyArray.h"
      #include #include void main(void)
      {
      // This behaves as expected
      Array iArrayA;

      for (int i = 0; i < 10; ++i)
      iArrayA.Add(i);
      for (int i = 0; i < 10; ++i)
      printf("%d\n", iArrayA[i]);

      // But this was returning odd results
      Array * iArrayB = new Array();

      for (int i = 0; i < 10; ++i)
      iArrayB->Add(i); // confirmed that the values were stored correctly
      for (int i = 0; i < 10; ++i)
      printf("%d\n", iArrayB[i]; // outputs were not what I expected

      delete iArrayB;

      system("pause");
      }

      Here is what I had to change it to to get the desired results:

      printf("%d\n", iArrayB[0][i]);

      What I don't get here is why when the array was declared as a local (Array<int> iArrayA;) did the accessor [] pull the stored int at the correct element but when I had the array declared as a pointer on the heap (Array<int> * iArrayB = new iArray();) the accessor [] was seemingly pulling random data until I added the [0] before the [i]? I am wondering if this has something to do with overloading the array subscript operator. Which is what has jumped out at me while I am writing this. Also, is there a way I can code the accessor to work for both locals and heap pointers? Is there any way around this?

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      private:
      T** _array;

      Why is this an array of pointers to T types, rather than just an array of T types? Woudl it not be better to have something like:

      T* _array;

      // ...

      _array = new T[CORE_ARRAY_DEFAULT_LENGTH];

      // ...

      T operator [] (int index) const
      {
      if ((index < 0) || (index >= _length))
      throw std::out_of_range("index");
      else
      return _array[index];
      }
      // etc

      F 1 Reply Last reply
      0
      • L Lost User

        private:
        T** _array;

        Why is this an array of pointers to T types, rather than just an array of T types? Woudl it not be better to have something like:

        T* _array;

        // ...

        _array = new T[CORE_ARRAY_DEFAULT_LENGTH];

        // ...

        T operator [] (int index) const
        {
        if ((index < 0) || (index >= _length))
        throw std::out_of_range("index");
        else
        return _array[index];
        }
        // etc

        F Offline
        F Offline
        Foothill
        wrote on last edited by
        #3

        For one, I've designed it to create heap copies of everything that gets added. This way it can handle both primitive data types and objects and be able to delete them. My first attempt at this used this approach but I ran into problems when trying to handle objects created on the heap. You can't delete primitives and if you don't delete heap objects, it leaks memory. By making it create all of its data on the heap no matter what get's passed in, I can avoid this problem. Edit: I got the T** _array; idea from my practice attempts with the DirectX SDK. I saw it use this approach all over the place.

        1 Reply Last reply
        0
        • F Foothill

          I am expanding my knowledge of class templates so I am building a very basic template of type Array<T>. I'll include only the code that pertains to the behavior that is confusing me. Template Header

          // MyArray.h

          #include #define CORE_ARRAY_DEFAULT_LENGTH 20

          template class Array
          {
          private:
          T** _array;
          int _size;
          int _length;

          public:
          Array(void)
          {
          _array = new T*[CORE_ARRAY_DEFAULT_LENGTH]();
          _size = CORE_ARRAY_DEFAULT_LENGTH;
          _length = 0;
          }
          ~Array(void) { Clear(); }

          int Size(void) const { return _size; }
          int Length(void) const { return _length; }

          T operator [] (int index) const
          {
          if ((index < 0) || (index >= _length))
          throw std::out_of_range("index");
          else
          return * _array[index];
          }

          void Add(T value)
          {
          if (_length == _size)
          Resize();

          _array[_length] = new T(value);
          ++_length;
          }

          /* Other functions follow CopyArray(), CloneArray(), Resize(), Clear(), InsertAt(), etc... */
          }

          And the source

          #include "MyArray.h"
          #include #include void main(void)
          {
          // This behaves as expected
          Array iArrayA;

          for (int i = 0; i < 10; ++i)
          iArrayA.Add(i);
          for (int i = 0; i < 10; ++i)
          printf("%d\n", iArrayA[i]);

          // But this was returning odd results
          Array * iArrayB = new Array();

          for (int i = 0; i < 10; ++i)
          iArrayB->Add(i); // confirmed that the values were stored correctly
          for (int i = 0; i < 10; ++i)
          printf("%d\n", iArrayB[i]; // outputs were not what I expected

          delete iArrayB;

          system("pause");
          }

          Here is what I had to change it to to get the desired results:

          printf("%d\n", iArrayB[0][i]);

          What I don't get here is why when the array was declared as a local (Array<int> iArrayA;) did the accessor [] pull the stored int at the correct element but when I had the array declared as a pointer on the heap (Array<int> * iArrayB = new iArray();) the accessor [] was seemingly pulling random data until I added the [0] before the [i]? I am wondering if this has something to do with overloading the array subscript operator. Which is what has jumped out at me while I am writing this. Also, is there a way I can code the accessor to work for both locals and heap pointers? Is there any way around this?

          F Offline
          F Offline
          Freak30
          wrote on last edited by
          #4

          The reason for the different behvior is that you can only override the accessor [] for an instance or reference but not for a pointer. Using [] on a pointer is always interpreted as pointer + index by the compiler. So the compiler thinks you have an array of Array. The usual syntax around this is

          printf("%d\n", (*iArrayB)[i]);

          This makes clear that iArrayB isn't an array but a pointer to a single object, and that you want to call the operator for the object it points to.

          The good thing about pessimism is, that you are always either right or pleasently surprised.

          F 1 Reply Last reply
          0
          • F Freak30

            The reason for the different behvior is that you can only override the accessor [] for an instance or reference but not for a pointer. Using [] on a pointer is always interpreted as pointer + index by the compiler. So the compiler thinks you have an array of Array. The usual syntax around this is

            printf("%d\n", (*iArrayB)[i]);

            This makes clear that iArrayB isn't an array but a pointer to a single object, and that you want to call the operator for the object it points to.

            The good thing about pessimism is, that you are always either right or pleasently surprised.

            F Offline
            F Offline
            Foothill
            wrote on last edited by
            #5

            Ah, I was thinking that it was something along those lines. I can see now that overloading the subscript operator is only good in certain situations. This doesn't sound like a good approach since it would require different code to access the data behind an object pointer then behind a local variable. I'll just change the accessor to a function.

            T GetValueAt(int index)
            {
            if (index < 0 || index >= _length)
            throw std::out_of_range("index");
            return *_array[index];
            }

            This should work just fine for what I am trying to do. This was informative, thank you.

            T 1 Reply Last reply
            0
            • F Foothill

              I am expanding my knowledge of class templates so I am building a very basic template of type Array<T>. I'll include only the code that pertains to the behavior that is confusing me. Template Header

              // MyArray.h

              #include #define CORE_ARRAY_DEFAULT_LENGTH 20

              template class Array
              {
              private:
              T** _array;
              int _size;
              int _length;

              public:
              Array(void)
              {
              _array = new T*[CORE_ARRAY_DEFAULT_LENGTH]();
              _size = CORE_ARRAY_DEFAULT_LENGTH;
              _length = 0;
              }
              ~Array(void) { Clear(); }

              int Size(void) const { return _size; }
              int Length(void) const { return _length; }

              T operator [] (int index) const
              {
              if ((index < 0) || (index >= _length))
              throw std::out_of_range("index");
              else
              return * _array[index];
              }

              void Add(T value)
              {
              if (_length == _size)
              Resize();

              _array[_length] = new T(value);
              ++_length;
              }

              /* Other functions follow CopyArray(), CloneArray(), Resize(), Clear(), InsertAt(), etc... */
              }

              And the source

              #include "MyArray.h"
              #include #include void main(void)
              {
              // This behaves as expected
              Array iArrayA;

              for (int i = 0; i < 10; ++i)
              iArrayA.Add(i);
              for (int i = 0; i < 10; ++i)
              printf("%d\n", iArrayA[i]);

              // But this was returning odd results
              Array * iArrayB = new Array();

              for (int i = 0; i < 10; ++i)
              iArrayB->Add(i); // confirmed that the values were stored correctly
              for (int i = 0; i < 10; ++i)
              printf("%d\n", iArrayB[i]; // outputs were not what I expected

              delete iArrayB;

              system("pause");
              }

              Here is what I had to change it to to get the desired results:

              printf("%d\n", iArrayB[0][i]);

              What I don't get here is why when the array was declared as a local (Array<int> iArrayA;) did the accessor [] pull the stored int at the correct element but when I had the array declared as a pointer on the heap (Array<int> * iArrayB = new iArray();) the accessor [] was seemingly pulling random data until I added the [0] before the [i]? I am wondering if this has something to do with overloading the array subscript operator. Which is what has jumped out at me while I am writing this. Also, is there a way I can code the accessor to work for both locals and heap pointers? Is there any way around this?

              V Offline
              V Offline
              Volynsky Alex
              wrote on last edited by
              #6

              Nice!

              1 Reply Last reply
              0
              • F Foothill

                Ah, I was thinking that it was something along those lines. I can see now that overloading the subscript operator is only good in certain situations. This doesn't sound like a good approach since it would require different code to access the data behind an object pointer then behind a local variable. I'll just change the accessor to a function.

                T GetValueAt(int index)
                {
                if (index < 0 || index >= _length)
                throw std::out_of_range("index");
                return *_array[index];
                }

                This should work just fine for what I am trying to do. This was informative, thank you.

                T Offline
                T Offline
                the_foobar
                wrote on last edited by
                #7

                Be careful, you are heavingly doing copy of your objects. You should pass T& when you add the object and return T& when you retrieve them. I would also suggest to have a const version of your accessor, returning 'const T&'.

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups