Programming C, C++, Java, PHP, Ruby, Turing, VB
Computer Science Canada 
Programming C, C++, Java, PHP, Ruby, Turing, VB  

Username:   Password: 
 RegisterRegister   
 [C++] Don't use arrays in C++!
Index -> Programming, C++ -> C++ Tutorials
Goto page 1, 2  Next
View previous topic Printable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic
Author Message
wtd




PostPosted: Sat Dec 18, 2004 3:02 pm   Post subject: [C++] Don't use arrays in C++!

But... don't you tell us to use arrays?

Yes, in Turing, and other languages, where arrays are either well-implemented, or there's simply no decent alternative.

C++ has a better alternative

The vector class in the Standard Template Library provides a more flexible, powerful alternative to using arrays.

Whoa, whoa, whoa... what's the Standard Template Library?

The STL is a collection of classes and functions which revolve around the C++ concept of templates, whereby we can create types and functions which operate on many types of data, without immediately specifying those types, or writing separate classes or functions for every type.

Don't worry, GCC includes an implementation of the STL, as do most other compilers these days. Visual C++ 6.0, it should be noted, has an implementation of it, but that implementation is quite bad. If you use this compiler, you may be led to believe the STL is a bad thing, when it's really the compiler at fault.

A simple template class

Now, we could write the following trivial code:

code:
#include <string>
#include <iostream>

class int_math
{
   private:
      int original;
   public:
      int_math(int original_) : original(original_) { }
      int add(int other) const { return original + other; }
      int value() const { return original; }
};

class double_math
{
   private:
      double original;
   public:
      double_math(double original_) : original(original_) { }
      double add(double other) const { return original + other; }
      double value() const { return original; }
};

int main()
{
   int_math a(8);
   double_math b(7.0);

   std::cout << a.add(5)
             << std::endl
             << b.add(41.3)
             << std::endl;

   return 0;
}


But, we should notice that we're duplicating a lot of code and this is a bad thing in programming, when it can be avoided. Fortunately C++ gives us a way to avoid code duplication in this instance.

code:
#include <string>
#include <iostream>

template <typename _t>
class math
{
   private:
      _t original;
   public:
      math(_t original_) : original(original_) { }
      _t add(_t other) const { return original + other; }
      _t value() const { return original; }
};

int main()
{
   math<int> a(8);
   math<double> b(7.0);

   std::cout << a.add(5)
             << std::endl
             << b.add(41.3)
             << std::endl;

   return 0;
};


Back to why arrays are bad

So, why are arrays bad, you ask. Well, reason number one is that they do not keep track of their own size. We have to do it manually, and that's just asking for trouble.

Consider an example where we want to ask for series of grades and find the average of them. We might get as many as ten, but we might get less, so we have to keep track of the number input.

code:
#include <iostream>

int main()
{
   int grades[10];
   int num_grades = 0;
   char answer = 'y';

   while (answer == 'y')
   {
      std::cin >> grades[num_grades];
      num_grades++;

      do
      {
         std::cout << "Enter another? ";
         std::cin >> answer;
      } while (!(answer == 'y' || answer == 'n'));
   }

   int sum = 0;

   for (int i = 0; int i < num_grades; i++)
   {
      sum += grades[i];
   }

   std::cout << "Average grade: " 
             << (sum / num_grades)
             << std::endl;

   return 0;
}


Now, let's look at the same example, using std::vector.

code:
#include <iostream>
#include <vector>

int main()
{
   std::vector<int> grades;
   char answer = 'y';

   while (answer == 'y')
   {
      int temp_grade;
      std::cin >> temp_grade;
      grades.push_back(temp_grade);

      do
      {
         std::cout << "Enter another? ";
         std::cin >> answer;
      } while (!(answer == 'y' || answer == 'n'));
   }

   int sum = 0;

   for (std::vector<int>::iterator i(grades.begin()); i != grades.end(); i++)
   {
      sum += *i;
   }

   std::cout << "Average grade: "
             << (sum / grades.size())
             << std::endl;
   return 0;
}


The important bits are:

code:
grades.push_back(temp_grade)


And:

code:
grades.size()


The first adds a new element (in this case a grade) onto the end of the vector. The second line grabs the size of the vector. The std::vector is just a class, so getting the size of one is as simple as calling a member function. Smile

Since std::vector is a class...

Of course, now that we've said that std::vector is just a class, this means we could implement a lot of features by simply subclassing std::vector.

code:
#include <iostream>
#include <vector>

class grades_collection : public std::vector<int>
{
   public:
      int sum()
      {
                 int sum = 0;

         for (iterator i(begin()); i != end(); i++)
         {
                sum += *i;
             }

             return sum;
      }

      int average()
      {
                 return sum() / size();
          }
};

int main()
{
   grades_collection grades;
   char answer = 'y';

   while (answer == 'y')
   {
      int temp_grade;
      std::cin >> temp_grade;
      grades.push_back(temp_grade);

      do
      {
         std::cout << "Enter another? ";
         std::cin >> answer;
      } while (!(answer == 'y' || answer == 'n'));
   }

   std::cout << "Average grade: "
             << grades.average()
             << std::endl;
   return 0;
}


Make it even simpler

We could simplify this even further by declaring a friend function which gets input and puts it into the vector.

code:
#include <iostream>
#include <vector>

class grades_collection : public std::vector<int>
{
   public:
      int sum()
      {
                 int sum = 0;

         for (iterator i(begin()); i != end(); i++)
         {
                sum += *i;
             }

             return sum;
      }

      int average()
      {
                 return sum() / size();
          }

          friend std::istream& operator>>(std::istream& in, grades_collection& g);
};

std::istream& operator>>(std::istream& in, grades_collection& g)
{
   int temp_grade;
   in >> temp_grade;
   g.push_back(temp_grade);
   return in;
}

int main()
{
   grades_collection grades;
   char answer = 'y';

   while (answer == 'y')
   {
      std::cin >> grades;

      do
      {
         std::cout << "Enter another? ";
         std::cin >> answer;
      } while (!(answer == 'y' || answer == 'n'));
   }

   std::cout << "Average grade: "
             << grades.average()
             << std::endl;
   return 0;
}


In Summary

There's more to come, but for now, we've seen that vectors offer a distinct advantage by knowing their own size.

We've also seen that their object-oriented nature makes it trivial to extend them, and this ability can make dealing with them much simpler.
Sponsor
Sponsor
Sponsor
sponsor
md




PostPosted: Sun Dec 19, 2004 2:42 pm   Post subject: (No subject)

Hmm, I've never used vectors, but I can see how they might be more useful than arrays. The only problem might be when you need to say quickly insert lots of data into the array. As I don't know how the vector class works I can't be sure, but it looks like it might need to allocate more memory when you add something, which is quite slow.

Is this actually the case, or are vectors on par speed wise with arrays?
wtd




PostPosted: Sun Dec 19, 2004 9:13 pm   Post subject: (No subject)

Vectors do automatically resize if you add more items than they can currently hold. Depending on the implementation of the STL that you're using, this can be pretty darn efficient.

One hint, though is that the std::vector constructor takes a number of items to hold.

code:
std::vector<int> grades(10);


Will create a vector called grades which can hold 10 integers. It can be resized later, of course, like any other vector, but if you don't exceed that number, it won't resize.
md




PostPosted: Sun Dec 19, 2004 9:56 pm   Post subject: (No subject)

Cool! And how do the iterators compare speed-wise? Obviously they arn't as fast as i++, but are they close?
wtd




PostPosted: Sun Dec 19, 2004 10:05 pm   Post subject: (No subject)

Cornflake wrote:
Cool! And how do the iterators compare speed-wise? Obviously they arn't as fast as i++, but are they close?


They're pretty much as fast. For anything but the absolute most critical system, where you're counting memory usage in bytes, you won't notice a difference.

Additionally, iterators are really cool.

How would you copy one array into another?

code:
int main()
{
   int foo[10], bar[10];

   for (int i = 0; i < 10; i++)
   {
      bar[i] = foo[i];
   }

   return 0;
}


Well, that's tedious.

How would you copy one vector into another?

code:
#include <vector>
#include <algorithm>

int main()
{
   std::vector<int> foo(10), bar(10);

   std::copy(foo.begin(), foo.end(), bar.begin());

   return 0;
}


Of course...

The copy function in the STL algorithm header is quite useful, because it can work on arrays too.

code:
#include <algorithm>

int main()
{
   int foo[10], bar[10];

   std::copy(foo, foo + 10, bar);

   return 0;
}
Martin




PostPosted: Sat Apr 16, 2005 12:32 pm   Post subject: (No subject)

++i is faster than i++
rizzix




PostPosted: Sat Apr 16, 2005 1:13 pm   Post subject: (No subject)

NO it isin't.. ++i increments the value and returns the incremnted value..

while i++ retuns the current value then increments it
wtd




PostPosted: Sat Apr 16, 2005 1:48 pm   Post subject: (No subject)

If you don't care about the return value, though, the prefix form is generally a bit faster. Both forms of the decrement operator offer the same performance.
Sponsor
Sponsor
Sponsor
sponsor
rizzix




PostPosted: Sat Apr 16, 2005 1:54 pm   Post subject: (No subject)

yes but in a for loop using ++i skips the initial value... or maybe not.
wtd




PostPosted: Sat Apr 16, 2005 1:57 pm   Post subject: (No subject)

code:
for (int i = 0; i < n; ++i) { ... }


Is identical in behavior to:

code:
for (int i = 0; i < n; i++) { ... }
rizzix




PostPosted: Sat Apr 16, 2005 2:08 pm   Post subject: (No subject)

so i guess there's no optimisation there. Razz
wtd




PostPosted: Sat Apr 16, 2005 2:45 pm   Post subject: (No subject)

Wrong, but thank you for playing our game.

Just because they behave the same way as far as we're concerned in this case doesn't mean they do the same thing at the machine level. Even though we don't use it, "i++" still makes a copy and returns it.
rizzix




PostPosted: Sat Apr 16, 2005 3:18 pm   Post subject: (No subject)

huh? y does it have to be that way?

what the compiler could do is return the current value and then increment the value in register. no need to return copys..

thats how Java handles it anyways.. i assumed it would be the same. my mistake.Embarassed although I think this is compiler dependent unless i'm mistaken again and the C++ languages it self enforces a copy returned... (which is just plain stupid imo)
Justin_




PostPosted: Wed Aug 16, 2006 3:35 pm   Post subject: (No subject)

What is the best way to get the integer value that represents the end of the vector?

I'm trying to do this:

c++:

vectorID[vectorID.end()].I_NEED_AN_INT();


What I have now is an iteration through the vector while keeping a count on it, then when it reaches end I'll have the integer representation of the end of the vector.
wtd




PostPosted: Wed Aug 16, 2006 5:41 pm   Post subject: (No subject)

You wish to retrieve the last element of a vector (that happens in this case to store ints)?
Display posts from previous:   
   Index -> Programming, C++ -> C++ Tutorials
View previous topic Tell A FriendPrintable versionDownload TopicRate TopicSubscribe to this topicPrivate MessagesRefresh page View next topic

Page 1 of 2  [ 27 Posts ]
Goto page 1, 2  Next
Jump to:   


Style:  
Search: