Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » STL vectors vs. arrays, new[], and malloc().

This thread is locked; no one can reply to it. rss feed Print
STL vectors vs. arrays, new[], and malloc().
Chris Amos
Member #3,235
February 2003
avatar

My question is simple.
With all of the usefullness of the STL and its containters, is there really any need for good old fashion arrays and data allocated with new? I mean, I use vectors for pretty much everything, just because im so used to them and they are so easy to use. Is there anything wrong with this? Reguardless of what the C purists might say, I think that there isn't.

~ Twisted Matrix

23yrold3yrold
Member #1,134
March 2001
avatar

Well, there's a bit of a speed boost with straight arrays, depending on what you're doing. And if you're not using any of the fancy functionality, making lots of vectors when you could easily get by using lots of arrays can bloat up your program, I imagine. My tilemap class in my editor uses vectors internally because they're easy to edit, but I use arrays in the game engine for speed, and because I don't need the STL functionality anymore.

Different tools for different situations.

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Korval
Member #1,538
September 2001
avatar

Quote:

With all of the usefullness of the STL and its containters, is there really any need for good old fashion arrays and data allocated with new?

Yes.

Regular C-arrays have several advantages.

#1: They're directly supported by the language (std::vector is not part of C++, but of the C++ standard-library).
#2: They're very simple to use. Simpler than std::vector (no iterators).
#3: The performance of C-arrays is as fast as you can possibly get.
#4: You can't save std::vectors as memory images in a file and load them directly on multiple platforms without having to do intermediate allocations.
#5: Vector's are typed; you can't play certain games with them that you can with arrays.
#6: The conventions for passing arrays around is well known. The behavior of std::vector when it is an argument is implementation-dependent.

I use vectors either for important arrays that are part of classes or for arrays that are going to resize themselves. I find little need for them other than for these cases.

Ceniza
Member #2,027
March 2002
avatar

Korval said:

#2: They're very simple to use. Simpler than std::vector (no iterators).

The interface of an array is also supported by std::vector and iterators act like pointers (even more, they are implemented just as simple pointers sometimes for std::vector), so using an iterator is like using a pointer and using std::vector is like using a C-array.

std::vector is the choice when you need to use a self-resizeable container with random access (or even better, direct access) to any element of it in constant time.

If you already know the size (or limit) of the vector/array and you know it won't change, you can use a simple C-array and you'll still be able to use it in STL algorithms, in this case pointers to elements of the C-array are just random access iterators.

Korval said:

#5: Vector's are typed; you can't play certain games with them that you can with arrays.

I don't get your point. What kind of game can be made using a C-array but not with std::vector?

Korval said:

#6: The conventions for passing arrays around is well known. The behavior of std::vector when it is an argument is implementation-dependent.

Ppl should be used to receive objects as references (or pointer to them), in that case I don't see the "implementation dependent" behavior in there, they'll act the same way as if you were receiving a C-array:

int feed_me(std::vector<int> & v)
{
  return *v.begin() + *(v.end() - 1);
}

int main()
{
  //...
  std::vector<int> g(10, 9);
  //...
  std::cout << feed_me(g) << std::endl;
  //...
}

If you didn't receive it as reference or pointer, you'd get a copy of it, something you couldn't do with C-arrays without creating a few helper functions first.

Bob
Free Market Evangelist
September 2000
avatar

Quote:

What kind of game can be made using a C-array but not with std::vector?

You can cast C arrays to arrays of other types - the bmp->line[] pointer is such an array. std::vector makes no garentee on the linearity of the actual memory organization, just that it gives the appearence of linearity from the API (and speed/memory) point of view.

--
- Bob
[ -- All my signature links are 404 -- ]

spellcaster
Member #1,493
September 2001
avatar

The point is:
std:vector is like using an array.

gcc will even inline the [] operator calls, so you won't see a difference in the generated code (just tried it).

What you should do is to check what data structure you need. And then use it. :)
If you need dynamic arrays use vector.
If you need static arrays use normal arrays.
If you need a stack, use the stack...

It's pretty straight forward.

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Ceniza
Member #2,027
March 2002
avatar

Bob: afaik std::vector has the property of linearity and that's one of the reasons it could store less elements than, for example, a std::deque.

Maybe it's just common implementation.

Seems it's time for checking the C++ standard documnet :)

...

Just checked it and seems they don't clarify it (or maybe I just didn't see it).

Now you're making me doubt :'(

Bad Bob.

Korval
Member #1,538
September 2001
avatar

Quote:

The interface of an array is also supported by std::vector and iterators act like pointers (even more, they are implemented just as simple pointers sometimes for std::vector), so using an iterator is like using a pointer and using std::vector is like using a C-array.

Iteraters are not pointers. If you treat them as pointers, you're begging for problems. Iteraters aren't guarenteed to be only a CPU word in size.

Quote:

Ppl should be used to receive objects as references (or pointer to them), in that case I don't see the "implementation dependent" behavior in there, they'll act the same way as if you were receiving a C-array:

What about the case of returning an array?

For a C-array, you just do:

int iArray[20];
int *FuncName()
{
  return iArray;
}

It is immediately obvious how to treat the return value. If you don't want someone to be able to change the return value, use a 'const int *FuncName()'. You are guarenteed that no copy operation will result, and that any changes you make will stick.

However, what about:

vector<int> iVec;
vector<int> &FuncName()
{
  return iVec;
}

Will this code result in a copy? Maybe; it depends on what they do on their end. It's far too easy for someone to do the wrong thing. Sure, you can do:

vector<int> iVec;
vector<int> *FuncName()
{
  return *iVec;
}

to virtually guarentee that a copy operation doesn't occur. However, if you've ever worked with a std::vector*, you'll know it's really annoying and ugly (->[] is not a normal thing, and adding in a lot of (*) is also annoying).

Quote:

If you didn't receive it as reference or pointer, you'd get a copy of it

Do you? Do std::vector's have copy symantics? Are you sure? Are you sure that some implementations aren't allowed to implicitly reference vectors?

Ceniza
Member #2,027
March 2002
avatar

Korval said:

Iteraters are not pointers. If you treat them as pointers, you're begging for problems. Iteraters aren't guarenteed to be only a CPU word in size.

Iterators for std::vector can be made with simple pointers, the implementation is free to do that and some must be doing that, the only thing is that you shouldn't trust they're always pointers: as said, it's implementation dependent, but once again, they could.

I didn't mean "iterators are pointers", I meant "pointers are iterators", random access iterators for being exact. "Everything that acts like an iterator is an iterator".

the same guy said:

What about the case of returning an array?

In #6 you were talking about it as an argument, there it depends of the form you receive it. When it's returned, things depend of the way you manipulate the received data and also of the exact return type.

In that point, right, when it's returned it's not like using a normal C-array.

still the same guy said:

Do you? Do std::vector's have copy symantics? Are you sure? Are you sure that some implementations aren't allowed to implicitly reference vectors?

If the implementation did such a thing, in the next code:

1#include <vector>
2#include <iostream>
3 
4using namespace std;
5 
6void tell(vector<int> i)
7{
8 cout << &i[0] << ' ';
9}
10 
11void tell2(vector<int> & i)
12{
13 cout << &i[0] << endl;
14}
15 
16int main()
17{
18 vector<int> a(10), b(20), c(30);
19 cout << "a: " << &a[0] << ' '; tell(a); tell2(a); //1
20 cout << "b: " << &b[0] << ' '; tell(b); tell2(b); //2
21 cout << "c: " << &c[0] << ' '; tell(c); tell2(c); //3
22}

if tell modified i (for changing values, removing, inserting...), it'd be also changing the internal stuff of a or b or c (whichever of those be sent) that wouldn't make any kind of sense there for the way it was received. That'd also mean the 3 columns (the one with cout, the one calling tell and the one calling tell2) for //1, //2 or //3 would show the same value, but in this case only the first and third column of each one would be the same, the second one is of a temporary object.

afaik, the only thing that could (it isn't forced by the standard) have Reference Counting is string, but it also has the property of "copy on write", so the first modification would make it create its own "independent" object.

If it also applied to vector, it'd need to comply with the "copy on write" model too.

Whenever it really happens or not, it'd need to be well-behaved.

[edit] It seems like everything is going off-topic now, I stop here [/edit]

Synapse Jumps
Member #3,073
December 2002

What I do in my game is use temporary vectors, then copy all the information from them into a pointer that has been created with new [ vector.size() ]. Because vectors are bigger and when I want to network a game, I can't send a vector because (I believe, I could be wrong) that they have pointers, and sending the address of something is no good.

Ceniza
Member #2,027
March 2002
avatar

Synapse Jumps said:

What I do in my game is use temporary vectors, then copy all the information from them into a pointer that has been created with new [ vector.size() ].

If std::vector really has the linearity "property", it wouldn't be necessary to copy all the elements from std::vector to a temporary C-array before sending them thru the network, you could just take the address of the first element and use it as a pointer to element (or "simulated" dynamic array if you prefer to call it that way):

std::vector<int> iv;
//...
int * piv = &iv[0];

Even though, after Bob's post, it's now in doubt if it'll work for all the implementations of std::vector.

Synapse Jumps said:

I can't send a vector because (I believe, I could be wrong) that they have pointers, and sending the address of something is no good.

Yep, trying to send an std::vector directly wouldn't work.

......

Believe Bob, believe book, believe none.

gillius
Member #119
April 2000

Someone was telling me that the standard does say the elements are linear or something to that effect.

Oh wait it says that accessing any element is O(1) time. That means there must be a direct mapping. Hmm I don't have my copy of the standard with me right now.

Anyway, if we are talking about performance you have to talk about an implementation of STL. And all the implementions I've seen store elements linearly in memory.

And I will bet you that using an iterator and accessing an vector using [] will generate the identical assembly code that an array would, at least for MSVC.NET. Adding elements will take more code than a C array if you don't allow resizing. I would prove it were I not on vacation ;).

Gillius
Gillius's Programming -- https://gillius.org/

Korval
Member #1,538
September 2001
avatar

Quote:

Adding elements will take more code than a C array if you don't allow resizing.

Don't you mean, "no more code"?

gillius
Member #119
April 2000

No. More code is generated for adding elements to the std::vector because it has to check to see if its size is too much.

If you take an example of you want to make an array of 50 elements. In the C method you allocate a new 50-element array and add 50 things to it. In the C++ method you do the same in a std::vector.

If you are using actual C, the C way is faster and generates less code. If you are using dynamic arrays in C++ with objects, then the array method may be SLOWER than the std::vector method because std::vector takes advantage of std::allocator and placement new to prevent redundant data copy. In the std::vector case with primitive objects, it will be slower than an array because of size checks, but the std::vector was is easier and safer imho and and speed decrease is worth it, and all of the speed advantages just make it better.

Gillius
Gillius's Programming -- https://gillius.org/

Korval
Member #1,538
September 2001
avatar

Quote:

In the std::vector case with primitive objects, it will be slower than an array because of size checks

Why wouldn't you be doing size checks with a C-array? Obviously, the array itself doesn't check, but why wouldn't the object doing the adding make sure that the user doesn't add too many? At least, in a debug build.

Chris Amos
Member #3,235
February 2003
avatar

I kindof awnsered my own question today. I tried to make a multidimentional array out of vectors and MSVC got mad at me, so I decided to just write a 2D array template class using new and delete and it works great and looks much cleaner then the iterator BS I surely would have had to write with the vector approach.

Anyone want to see the class? Mabey you can tell me how to better it a little? OK!! You convinced me. here it is you nags! :D

1/*** Creates and destroys a dynamic 2D array ***/
2template <class QType> class array2D
3{
4public:
5 QType **ptr;
6
7 int height;
8 int width;
9 
10 array2D() {}
11 ~array2D();
12 array2D( int w, int h ) { resize(w,h); }
13 void resize( int w, int h ) ;
14 inline QType at( int x, int y ) ;
15};
16 
17/*****************************************************/
18template <class QType> void array2D<QType>::resize( int w, int h )
19{
20 ptr= new QType *[h];
21 for( int y=0; y<h; y++) {
22 ptr[y] = new QType [w];
23 }
24 height=h;
25 width=w;
26}
27 
28template <class QType> array2D<QType>::~array2D()
29{
30 for ( int y = 0; y < height; y++) {
31 delete [] ptr[y];
32 }
33 delete [] ptr;
34}
35 
36template <class QType> inline QType array2D<QType>::at( int x, int y )
37{
38 if ( (x<0) || (y<0) || (x>(width-1)) || (y>(height-1)) )
39 // ERROR
40 return ptr[x][y]
41}

~ Twisted Matrix

Ceniza
Member #2,027
March 2002
avatar

You shouldn't really get that a slow down for inserting, say those 50, elements in an std::vector if you're going to do it in a ~C way:

std::vector<int> vi(50);
for (int i = 0; i < 50; ++i)
{
  vi<i> = i * 2;
}

operator [] won't check if the index is valid or not, so if you use an invalid index, it won't be std::vector's fault if the program crashes.

If you want range checking you need to use at(), that will return an exception of type std::out_of_range in case you use an invalid index, method that would be slow compared to using operator [], but safer.

The other method that would cause a slow down, but at the same time would give you more safety, is using push_back().

-----------------

I was checking one of my little precious books and found the "answer" to Bob's comment:

my little precious book said:

Contiguity of Vectors
Built-in arrays in C++ reside in contiguous chunks of memory. The Standard, however, does not require that vector elements occupy contiguous memory. When STL was added to the Standard, it seemed intuitive that vectors should store their elements contiguously, so contiguity never became an explicit requirement. Indeed, all current STL implementations follow this convention. The current specification, however, permits implementations that do not use contiguous memory. This loophole will probably be fixed by the Standardization committee in the future, and vector contiguity will become a Standard requirement.

So you can make the assumption but you can't be 100% sure :-/

spellcaster
Member #1,493
September 2001
avatar

Regarding the 2d array class:

You should use a virtual constructor, declare a copy ctor and an opertator=

Other than that, it looks ok at the first glance ;)

--
There are no stupid questions, but there are a lot of inquisitive idiots.

Go to: