Speed of Basic Arrays Versus Vectors ...

Hello,

A little exersize I did recently which essentially compares the speed of arrays versus vectors.

I test the creation, usage, and deletion speeds of vectors and arrays and the results are printed on screen.

Long story short, when programming in debug mode there is a HUGE difference between arrays (faster) and vectors (slower) but when programming in release mode that difference is mostly wiped out with arrays only having an extremely small advantage.

Considering all of the other advantages that you get with vectors there should be no reason why people don't use them.

Anyway, just thought I would post to help someone else out there with learning C++.

You should be able to paste the below code in an empty file, compile, and run.

CODE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*

Header...

*/

#include <iostream>
#include <vector>
#include <string>
#include <time.h>

class SimpleClass;

class TimeTest;

class SimpleClass {
public:
	SimpleClass();
	~SimpleClass();
	void PrintLineToScreen(std::string LineToWrite);
	void AddToInternalCounter();
private:
	int InternalCounter;
};

void SimpleClass::PrintLineToScreen(std::string LineToWrite) {
	std::cout << LineToWrite << "/n" << std::endl;
}

SimpleClass::SimpleClass() {
	InternalCounter = 0;
}

SimpleClass::~SimpleClass() {
	InternalCounter = -1;
}

void SimpleClass::AddToInternalCounter() {
	InternalCounter += 1;
}

class TimeTest {

public:

	TimeTest(int NumberOfClasses);
	TimeTest();
	~TimeTest();
	void CreateArray();
	void EmptyArray();
	void IterateCounterArray();
	void IterateCounterVector();
	void FillVector();
	void EmptyVector();
private:
	int NumberOfClassesToCreate;
	clock_t RawTime;
	clock_t StartTime;
	clock_t DeltaTime;
	SimpleClass* ArrayOfClasses;
	std::vector<SimpleClass> VectorOfClasses;
};

TimeTest::TimeTest(int NumberOfClasses) {
	NumberOfClassesToCreate = NumberOfClasses;
}

TimeTest::TimeTest() {
	NumberOfClassesToCreate = 1000000;
}

TimeTest::~TimeTest() {

}

void TimeTest::CreateArray() {
	StartTime = clock();
	ArrayOfClasses = new SimpleClass[NumberOfClassesToCreate];
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::EmptyArray() {
	StartTime = clock();
	delete [] ArrayOfClasses;
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to delete " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::FillVector() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		SimpleClass NewClassToAdd;
		VectorOfClasses.push_back(NewClassToAdd);
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::EmptyVector() {
	StartTime = clock();
	if (VectorOfClasses.size() > 0) {
		VectorOfClasses.empty();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to empty " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::IterateCounterArray() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		ArrayOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::IterateCounterVector() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		VectorOfClasses.at(i).AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

/*

Main Function.

*/

int main(int argc, char** argv) {
	
	TimeTest Tester(10000000);
	Tester.CreateArray();
	system("pause");
	Tester.FillVector();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.EmptyArray();
	system("pause");
	Tester.EmptyVector();
	system("pause");

	exit(EXIT_SUCCESS);
}
If you know how many items will be added to the vector you should use reserve to reduce the overhead of the following push_backs.

 
VectorOfClasses.reserve(NumberOfClassesToCreate);

In this case you don't really need the push_backs, you could simply add all elements in one function call, using resize.

 
VectorOfClasses.resize(NumberOfClassesToCreate);

The at function do bounds checking so it's not fair to compare it with an array. A more fair comparison would be to use vector's operator[].

Your test is broken. You need to do something to prevent the compiler from optimizing away too much. When I run your program the timings are about the same no matter what value I give to NumberOfClassesToCreate.
Last edited on
Thanks for the feedback; I edited the program and used both the reserve method as well as the resize method.

I also changed the iterator for the vector per your bounds checking suggestion.

See my edited code example below; I don't know what else I can do to improve my testing example as of right now. I am learning myself.

Any more suggestions from folks most welcome:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*

Header.

*/

#include <iostream>
#include <vector>
#include <string>
#include <time.h>

class SimpleClass;

class TimeTest;

class SimpleClass {
public:
	SimpleClass();
	~SimpleClass();
	void PrintLineToScreen(std::string LineToWrite);
	void AddToInternalCounter();
private:
	int InternalCounter;
};

void SimpleClass::PrintLineToScreen(std::string LineToWrite) {
	std::cout << LineToWrite << "/n" << std::endl;
}

SimpleClass::SimpleClass() {
	InternalCounter = 0;
}

SimpleClass::~SimpleClass() {
	InternalCounter = -1;
}

void SimpleClass::AddToInternalCounter() {
	InternalCounter += 1;
}

class TimeTest {

public:

	TimeTest(int NumberOfClasses);
	TimeTest();
	~TimeTest();
	void CreateArray();
	void EmptyArray();
	void IterateCounterArray();
	void IterateCounterVector();
	void FillVectorReserve();
	void FillVectorResize();
	void EmptyVector();
private:
	int NumberOfClassesToCreate;
	clock_t RawTime;
	clock_t StartTime;
	clock_t DeltaTime;
	SimpleClass* ArrayOfClasses;
	std::vector<SimpleClass> VectorOfClasses;
};

TimeTest::TimeTest(int NumberOfClasses) {
	NumberOfClassesToCreate = NumberOfClasses;
}

TimeTest::TimeTest() {
	NumberOfClassesToCreate = 1000000;
}

TimeTest::~TimeTest() {

}

void TimeTest::CreateArray() {
	StartTime = clock();
	ArrayOfClasses = new SimpleClass[NumberOfClassesToCreate];
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::EmptyArray() {
	StartTime = clock();
	delete [] ArrayOfClasses;
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to delete " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::FillVectorReserve() {
	StartTime = clock();
	VectorOfClasses.reserve(NumberOfClassesToCreate);
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		SimpleClass NewClassToAdd;
		VectorOfClasses.push_back(NewClassToAdd);
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via std::vector 'Reserve' method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::FillVectorResize() {
	StartTime = clock();
	VectorOfClasses.resize(NumberOfClassesToCreate);
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via std::vector 'Resize' method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::EmptyVector() {
	StartTime = clock();
	if (VectorOfClasses.size() > 0) {
		VectorOfClasses.empty();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to empty " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::IterateCounterArray() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		ArrayOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via old array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

void TimeTest::IterateCounterVector() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		VectorOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl;
}

/*

Main function.

*/

int main(int argc, char** argv) {
	
	TimeTest Tester(10000000);
	Tester.CreateArray();
	system("pause");
	Tester.FillVectorReserve();
	system("pause");
	Tester.EmptyArray();
	system("pause");
	Tester.EmptyVector();
	system("pause");
	Tester.CreateArray();
	system("pause");
	Tester.FillVectorResize();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.IterateCounterArray();
	system("pause");
	Tester.IterateCounterVector();
	system("pause");
	Tester.EmptyArray();
	system("pause");
	Tester.EmptyVector();
	system("pause");

	exit(EXIT_SUCCESS);
}
You aren't really measuring the time to create & destroy a vector vs. an array for 2 reasons. First, because your vector/array contains a class with a destructor, most of the time is probably taken up by destroying the items *in* the container, not the container itself. Second, in my opinion you aren't really using arrays, you're using pointers to dynamically allocated arrays.

So you might want to try another set of tests where the array size is known at compile time. If you use a fix-length array of int, I think you'll find that the time to create & destroy the array is very small compared to a vector.
On your two points; I wanted to measure usage of real world classes with constructors/destructors and dynamically created arrays.

I hope not to start an argument by saying this but most of the time the arrays you want/need to use don't have fixed sizes. Therefore IMHO it is important to test as you are going to use them vs testing in an ideal scenario where arrays have fixed sizes.

That being said; I altered the example to include a test of fixed array sizes.

See below for the updated code example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#include <iostream>
#include <vector>
#include <string>
#include <time.h>

#define FIXED_ARRAY_SIZE 10000000

class TimeTest;
class SimpleClass;

class SimpleClass {
public:
	SimpleClass();
	~SimpleClass();
	void PrintLineToScreen(std::string LineToWrite);
	void AddToInternalCounter();
private:
	int InternalCounter;
};

class TimeTest {

public:
	TimeTest(int NumberOfClasses);
	TimeTest();
	~TimeTest();
	void CreateArray();
	void CreateFixedArray();
	void EmptyArray();
	void EmptyFixedArray();
	void IterateCounterArray();
	void IterateCounterFixedArray();
	void IterateCounterVector();
	void FillVectorReserve();
	void FillVectorResize();
	void EmptyVector();
private:
	int NumberOfClassesToCreate;
	clock_t RawTime;
	clock_t StartTime;
	clock_t DeltaTime;
	SimpleClass* ArrayOfClasses;
	SimpleClass* FixedArrayOfClasses;
	std::vector<SimpleClass> VectorOfClasses;
};

void SimpleClass::PrintLineToScreen(std::string LineToWrite) {
	std::cout << LineToWrite << "/n" << std::endl;
}

SimpleClass::SimpleClass() {
	InternalCounter = 0;
}

SimpleClass::~SimpleClass() {
	InternalCounter = -1;
}

void SimpleClass::AddToInternalCounter() {
	InternalCounter += 1;
}

TimeTest::TimeTest(int NumberOfClasses) {
	NumberOfClassesToCreate = NumberOfClasses;
}

TimeTest::TimeTest() {
	NumberOfClassesToCreate = 1000000;
}

TimeTest::~TimeTest() {

}

void TimeTest::CreateArray() {
	StartTime = clock();
	ArrayOfClasses = new SimpleClass[NumberOfClassesToCreate];
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via old 'dynamically allocated' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::CreateFixedArray() {
	StartTime = clock();
	FixedArrayOfClasses = new SimpleClass[FIXED_ARRAY_SIZE];
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << FIXED_ARRAY_SIZE << " SimpleClass classes via old 'fixed size' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::EmptyArray() {
	StartTime = clock();
	delete[] ArrayOfClasses;
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to delete " << NumberOfClassesToCreate << " SimpleClass classes via old 'dynamically allocated' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::EmptyFixedArray() {
	StartTime = clock();
	delete[] FixedArrayOfClasses;
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to delete " << FIXED_ARRAY_SIZE << " SimpleClass classes via old 'fixed size' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::FillVectorReserve() {
	StartTime = clock();
	VectorOfClasses.reserve(NumberOfClassesToCreate);
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		SimpleClass NewClassToAdd;
		VectorOfClasses.push_back(NewClassToAdd);
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via std::vector 'Reserve' method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::FillVectorResize() {
	StartTime = clock();
	VectorOfClasses.resize(NumberOfClassesToCreate);
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to create " << NumberOfClassesToCreate << " SimpleClass classes via std::vector 'Resize' method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::EmptyVector() {
	StartTime = clock();
	if (VectorOfClasses.size() > 0) {
		VectorOfClasses.empty();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to empty " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::IterateCounterArray() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		ArrayOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via old 'dynamically allocated' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::IterateCounterFixedArray() {
	StartTime = clock();
	for (int i = 0; i < FIXED_ARRAY_SIZE; i++) {
		FixedArrayOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << FIXED_ARRAY_SIZE << " SimpleClass classes via old 'fixed size' array method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

void TimeTest::IterateCounterVector() {
	StartTime = clock();
	for (int i = 0; i < NumberOfClassesToCreate; i++) {
		VectorOfClasses[i].AddToInternalCounter();
	}
	RawTime = clock();
	DeltaTime = RawTime - StartTime;
	std::cout << "Time it took to add to the internal counters of " << NumberOfClassesToCreate << " SimpleClass classes via std::vector method." << std::endl;
	std::cout << float(DeltaTime) << std::endl << std::endl;
}

int main(int argc, char** argv) {
	
	TimeTest Tester(10000000);
	Tester.CreateArray();
	Tester.CreateFixedArray();
	Tester.FillVectorReserve();
	Tester.EmptyArray();
	Tester.EmptyFixedArray();
	Tester.EmptyVector();
	Tester.CreateArray();
	Tester.CreateFixedArray();
	Tester.FillVectorResize();
	Tester.IterateCounterArray();
	Tester.IterateCounterFixedArray();
	Tester.IterateCounterVector();
	Tester.EmptyArray();
	Tester.EmptyFixedArray();
	Tester.EmptyVector();
	system("pause");

	exit(EXIT_SUCCESS);
}
I wanted to measure usage of real world classes with constructors/destructors and dynamically created arrays.

These are certainly real-world examples, but I worry that the differences between arrays and vectors will be dwarfed by the time required to construct/destroy the items in the container. On the other hand, that, in itself, may be instructive. In other words, the choice of the container may not matter much if the contained items are at all complex.

Most of the time the arrays you want/need to use don't have fixed sizes.

That depends on the application of course. I think the important thing is to understand exactly what you're comparing so you know when to apply the results.

Cool stuff. Thanks for doing this and showing the results.
Topic archived. No new replies allowed.