Using arrays or std::vectors in C++, what's the performance gap?
Asked Answered
O

22

256

In our C++ course they suggest not to use C++ arrays on new projects anymore. As far as I know Stroustrup himself suggests not to use arrays. But are there significant performance differences?

Operable answered 19/12, 2008 at 17:30 Comment(7)
Why would you think there is a performance gap.Carver
Because usually with better functionality comes worst performance.Operable
I agree about premature optimisation but choosing the better storage method up front makes a lot of sense. Often in the real world the code needs to be shipped and the next product developed and the optimisation step never happens.Kikuyu
i wish people would stop screaming "premature optimization!" whenever someone is asking a simple question related to performance! answer the question and don't just PREMATURELY assume people are doing anything prematurely.Unsaddle
@d7samaurai: agree, I've yet to see anyone try using int main(int argc, const std::vector<string>& argv)Tragic
@MarkKCowan For general code, this is clearly premature optimization!Emissary
@Operable with great power comes great responsibilityGehman
N
226

Using C++ arrays with new (that is, using dynamic arrays) should be avoided. There is the problem that you have to keep track of the size, and you need to delete them manually and do all sorts of housekeeping.

Using arrays on the stack is also discouraged because you don't have range checking, and passing the array around will lose any information about its size (array to pointer conversion). You should use std::array in that case, which wraps a C++ array in a small class and provides a size function and iterators to iterate over it.

Now, std::vector vs. native C++ arrays (taken from the internet):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

Note: If you allocate arrays with new and allocate non-class objects (like plain int) or classes without a user defined constructor and you don't want to have your elements initialized initially, using new-allocated arrays can have performance advantages because std::vector initializes all elements to default values (0 for int, for example) on construction (credits to @bernie for reminding me).

Narrowminded answered 19/12, 2008 at 17:41 Comment(14)
Who invented the damn AT&T syntax? Only if I knew... :)Chthonian
Note that std::tr1::array (or boost::array) can resolve cases where you would have used native array with new.Amylo
This is not true for the Visual C++ compiler. But for GCC it is.Deductive
The point in my answer is that vector doesn't have to be slower than correponding pointer operations. Of course, it can be (easy to achieve by enabling enable debug mode, too) :)Narrowminded
+1 for "Indexing a vector is the same damn thing as indexing a pointer." and for the other conclusions as well.Sandalwood
ok, this comes a bit late, but still: No issues with the AT&T syntax on my side -- coming from old 68k assembly language, it seemed a lot more natural to me to use a move from, to syntaxStockwell
@Stockwell I'm not going to argue with you, but when you learn assembly after learning higher level languages, Intel syntax just makes a lot more sense than some backwards, prefixed (numbers), suffixed (instructions), and obscure (accessing memory) nature of AT&T syntax.Cyrillus
This performance comparison does not take into account the initial allocation of the std::vector vs an array. See my answer for more details: https://mcmap.net/q/109480/-using-arrays-or-std-vectors-in-c-what-39-s-the-performance-gapArrogant
@Arrogant the question does not specify how the array is allocated. i can't compare the initial allocation const of std::vector to something that is not specified. If the array is allocated on the stack, obviously std::vector's allocation cost is higher. But if the array is allocated with new, I don't think it would make a difference what you use.Narrowminded
@Arrogant I see you refer to the initialization issue. i added a paragraph to the answerNarrowminded
I don't think the usage of Dynamic arrays should be discouraged just because people have to learn how to use a delete. I mean, this is just the way it is. It does not mean the feature is bad or dangerous, it just means the programmer has to know how to actually program.Widgeon
Putting the int* inside a struct means you never have a function taking just an int* arg, or length, pointer as separate args. std::vector can't do that because its 3 pointers are tied together as a single object that can't be split into 3 separate register args. godbolt.org/z/TddYMfzE5 shows just mov eax, [rdi+12] for ptr[3] vs. the extra level of indirection from passing a std::vector<int> &v. (Because passing it by value would be even worse). Of course after inlining into a loop, the base address for the data is probably in a register either way.Palsy
The last point about C++ vectors being initialized can be avoided by increasing the vector capacity using reserve in combination with push_back.Nemertean
@Nemertean push_back in a loop can incnur other overheads thoughJarodjarosite
P
94

Preamble for micro-optimizer people

Remember:

"Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%".

(Thanks to metamorphosis for the full quote)

Don't use a C array instead of a vector (or whatever) just because you believe it's faster as it is supposed to be lower-level. You would be wrong.

Use by default vector (or the safe container adapted to your need), and then if your profiler says it is a problem, see if you can optimize it, either by using a better algorithm, or changing container.

This said, we can go back to the original question.

Static/Dynamic Array?

The C++ array classes are better behaved than the low-level C array because they know a lot about themselves, and can answer questions C arrays can't. They are able to clean after themselves. And more importantly, they are usually written using templates and/or inlining, which means that what appears to a lot of code in debug resolves to little or no code produced in release build, meaning no difference with their built-in less safe competition.

All in all, it falls on two categories:

Dynamic arrays

Using a pointer to a malloc-ed/new-ed array will be at best as fast as the std::vector version, and a lot less safe (see litb's post).

So use a std::vector.

Static arrays

Using a static array will be at best:

  • as fast as the std::array version
  • and a lot less safe.

So use a std::array.

Uninitialized memory

Sometimes, using a vector instead of a raw buffer incurs a visible cost because the vector will initialize the buffer at construction, while the code it replaces didn't, as remarked bernie by in his answer.

If this is the case, then you can handle it by using a unique_ptr instead of a vector or, if the case is not exceptional in your codeline, actually write a class buffer_owner that will own that memory, and give you easy and safe access to it, including bonuses like resizing it (using realloc?), or whatever you need.

Psalmody answered 20/12, 2008 at 17:35 Comment(15)
Thanks for addressing static arrays as well - std::vector is useless if you're not allowed to dynamically allocate memory for performance reasons.Vito
When you say "Using a static array will be at best as fast as the boost::array version" it shows how biased you are. It should be the other around, Boost:array can be at best fast like static arrays.Deductive
@Deductive : It is a misunderstanding: You should read it as "Using a static array will be at best ((as fast as the boost::array version) && (a lot less safe))". I'll edit the post to clarify this. By the way, thank you for the benefit of the doubt.Psalmody
Use the boost version (unless you have issues using boost for some arbitrary political reason) - FTFYTswana
I came from a software editor where boost was out of question for strange reasons, and arrived in a softwae editor where boost is, well, more or less out of question, too... :-/ ... I'm a lucky guy! I just need to find where my luck went... :-)Psalmody
what about std::array?Eyehole
Always show the full quote. "Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%." Otherwise it becomes a meaningless soundbite.Blavatsky
@metamorphosis, never knew it wasn't a full quote! Thank you for sharing!Naphtha
@Blavatsky : Thanks for the full quote. Actually, I was quoting from a variation of it! "Premature optimization is the root of all evil, as is premature pessimization", from Sutter and Alexandrescu (IIRC). I'll update my answer to put the full quote.Psalmody
Your comparison of dynamic array vs vector does not take into account the initial allocation of the std::vector vs an array. See my answer for more details: https://mcmap.net/q/109480/-using-arrays-or-std-vectors-in-c-what-39-s-the-performance-gapArrogant
@Arrogant : Your case is a edge-case. And it can be easily solved. Using the standard library: Just malloc your buffer, put it in a smart pointer (say, unique_ptr<char[], FreeDeleter>, and be done with it.Writing your own class: use a vector like interface when relevant, and add the "realloc" feature for giggles and fun. All in all, To be frank, when you code in C++, you rarely use an uninitialized buffer, for multiple, very good reasons. 99% of the uses can (and were when possible) replaced by vector without any visible cost. For the 1% remaining, C++ lets you customize the best solution.Psalmody
@Psalmody Yes it can be considered an edge case, but it does exist in real code. And yes using a unique_ptr is the way to go to manage the deletion but that's orthogonal to this question. An uninitialized buffer can be useful when it's meant to be the destination of a memcpy.Arrogant
@Arrogant : I added the edge case in my answer. Thanks.Psalmody
@Psalmody define an allocator and overload the 'construct' method that skips initialization upon default construction request on in-built types. Then use the custom allocator as 2nd template parameter to vector; edge climbed.Demur
I'm not alone in thinking way too many waffle on about premature optimisation. Part of using c++ over, say, python or lisp is optimization. You should always have an eye on performance depending on the end goals. It is not a crime to consider performance on key project data structures.Frosting
K
39

Vectors are arrays under the hood. The performance is the same.

One place where you can run into a performance issue, is not sizing the vector correctly to begin with.

As a vector fills, it will resize itself, and that can imply, a new array allocation, followed by n copy constructors, followed by about n destructor calls, followed by an array delete.

If your construct/destruct is expensive, you are much better off making the vector the correct size to begin with.

There is a simple way to demonstrate this. Create a simple class that shows when it is constructed/destroyed/copied/assigned. Create a vector of these things, and start pushing them on the back end of the vector. When the vector fills, there will be a cascade of activity as the vector resizes. Then try it again with the vector sized to the expected number of elements. You will see the difference.

Kandrakandy answered 19/12, 2008 at 18:17 Comment(7)
Pendantry: the performance has the same big O. std::vector does a little bit of bookkeeping, which presumably cost a small amount of time. OTOH, you end up doing much of the same bookkeeping when rolling your own dynamic arrays.Sulphide
yes i understand. The thrust of his question though, was what are the performance differences..... I attempted to address that.Kandrakandy
Gcc's std::vector does indeed increase the capacity one-by-one if you call push_back.Despotism
@Despotism Then gcc's std::vector sounds standards-non-compliant? I believe the standard requires that vector::push_back have amortized constant complexity, and increasing capacity by 1 on each push_back is going to be n^2 complexity after you account for reallocs. -- presuming some kind of exponential capacity increase on push_back and insert, a failure to reserve will lead to at most a constant factor increase in vector content copies. A 1.5 exponential vector growth factor would mean ~3x as many copies if you failed to reserve().Ichthyosaur
@Yakk: According to the standard it has linear complexity for each insertion call, but not over several independent insertions. This only plays a role if you insert several elements by calling std::vector::insert. Reserving more memory than actually required, could cause problems on systems with limited memory. That's probably the reason why the standard does not require that. In fact, I also expected exponential growth with GCC's STL as it is not forbidden by the standard. That's why I looked into the std::vector sources in the first place.Despotism
@Despotism you are wrong. The standard forbids exponential growth: § 23.2.3 paragraph 16 says "Table 101 lists operations that are provided for some types of sequence containers but not others. An implementation shall provide these operations for all container types shown in the “container” column, and shall implement them so as to take amortized constant time." (table 101 is the one with push_back in it). Now please stop spreading FUD. No mainstream implementation violates this requirement. Microsoft's standard C++ library grows with a 1.5x factor, and GCC grows with a 2x factor.Midlands
@R.MartinhoFernandes: It's exactly these growing factors I wished to find out when I looked into the sources of std::vector. It's quite some time ago I did this so I cannot remember the details. When I find time I will revisit the current version of the code.Despotism
E
33

To respond to something Mehrdad said:

However, there might be cases where you still need arrays. When interfacing with low level code (i.e. assembly) or old libraries that require arrays, you might not be able to use vectors.

Not true at all. Vectors degrade nicely into arrays/pointers if you use:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

This works for all major STL implementations. In the next standard, it will be required to work (even though it does just fine today).

Eugenioeugenius answered 19/12, 2008 at 17:47 Comment(10)
why do you think it isn't required to work nowadays? &*v.begin() will give you a pointer to the start of the internal buffer of the vector, and it's contiguous. what will change is std::string, which will be required to be contiguous (or so ppl told me)Narrowminded
The current standard says no such thing. It is implied, and it is implemented as continuous storage. But the standard merely says that it is a random access container (using iterators). The next standard will be explicit.Eugenioeugenius
&*v.begin() merely applies the & operator to the result of de-referencing the iterator. De-referencing can return ANY type. Using the address-of operator can again return ANY type. The standard does not define this as a pointer into a contiguous area of memory.Eugenioeugenius
Original 1998 text of the Standard indeed did not require it, but there was an addendum in 2003 that addresses this, so it is really covered by the Standard. herbsutter.wordpress.com/2008/04/07/…Eggshell
+1 for Nemanja's comment. Also, it's a mostly academic debate for some time now; all modern stl libs have 'done the right thing' for some time.Waki
C++03 says explicitly that &v[n] == &v[0] + n is valid provided n is within the size range. The paragraph containing this statement didn't change with C++11.Despotism
@FrankKrueger: What if you have vector<vector<double>>? How can you point with a pointer?Chatter
why not just use std::vector::data()?Eyehole
And how about the other way? Given a pointer from low level code (or C-Export DLL), you will not be able to wrap a vector around it without copying.Toratorah
@Manolete: Generally don't use nested vectors of vectors or arrays of pointers in the first place when you want a 2D array; if you have a flat 1D std::vector<double>, you can pass that to a C interface expecting size_t width, double arr2d[width][]. Of course, in a C++ implementation without VLAs, the 2nd parameter would have to actually be declared as void* or double* or something, with the 2D array only being visible to C99 code, because you couldn't cast vec.data() to a pointer-to-variable-length-array.Palsy
C
23

You have even fewer reasons to use plain arrays in C++11.

There are 3 kind of arrays in nature from fastest to slowest, depending on the features they have (of course the quality of implementation can make things really fast even for case 3 in the list):

  1. Static with size known at compile time. --- std::array<T, N>
  2. Dynamic with size known at runtime and never resized. The typical optimization here is, that if the array can be allocated in the stack directly. -- Not available. Maybe dynarray in C++ TS after C++14. In C there are VLAs
  3. Dynamic and resizable at runtime. --- std::vector<T>

For 1. plain static arrays with fixed number of elements, use std::array<T, N> in C++11.

For 2. fixed size arrays specified at runtime, but that won't change their size, there is discussion in C++14 but it has been moved to a technical specification and made out of C++14 finally.

For 3. std::vector<T> will usually ask for memory in the heap. This could have performance consequences, though you could use std::vector<T, MyAlloc<T>> to improve the situation with a custom allocator. The advantage compared to T mytype[] = new MyType[n]; is that you can resize it and that it will not decay to a pointer, as plain arrays do.

Use the standard library types mentioned to avoid arrays decaying to pointers. You will save debugging time and the performance is exactly the same as with plain arrays if you use the same set of features.

Counterbalance answered 29/10, 2013 at 13:22 Comment(2)
std::dynarray .After reviewing national body comments to n3690, this library component was voted out from C++14 working paper into a separate Technical Specification. This container is not a part of the draft C++14 as of n3797. from en.cppreference.com/w/cpp/container/dynarrayRichy
very good answer. brief and summarizing , yet more details than any.Richy
A
11

There is definitely a performance impact to using an std::vector vs a raw array when you want an uninitialized buffer (e.g. to use as destination for memcpy()). An std::vector will initialize all its elements using the default constructor. A raw array will not.

The C++ specification for the std:vector constructor taking a count argument (it's the third form) states:

`Constructs a new container from a variety of data sources, optionally using a user supplied allocator alloc.

  1. Constructs the container with count default-inserted instances of T. No copies are made.

Complexity

2-3) Linear in count

A raw array does not incur this initialization cost.

Note that with a custom allocator, it is possible to avoid "initialization" of the vector's elements (i.e. to use default initialization instead of value initialization). See these questions for more details:

Arrogant answered 13/5, 2017 at 16:0 Comment(3)
But this point is why my small_vector class has a resize overload that default constructs the data, rather than value constructing like all the normal methods.Jarodjarosite
This answer would be better if you made a clearer distinction about default construction vs value construction. std::vector will always value construct, which can have slight overhead in a few edge cases. In the constructor bit you cited, the vector value constructs, despite the implication that it default constructs, which is super annoying.Jarodjarosite
@MooingDuck I won't repeat here what is explained in great detail already in many places. However, I did add more information to show that a custom allocator can be used to achieve default initialization.Arrogant
C
7

Go with STL. There's no performance penalty. The algorithms are very efficient and they do a good job of handling the kinds of details that most of us would not think about.

Camellia answered 19/12, 2008 at 17:41 Comment(0)
P
7

About duli's contribution with my own measurements.

The conclusion is that arrays of integers are faster than vectors of integers (5 times in my example). However, arrays and vectors are arround the same speed for more complex / not aligned data.

Precision answered 19/4, 2012 at 17:12 Comment(0)
C
6

STL is a heavily optimized library. In fact, it's even suggested to use STL in games where high performance might be needed. Arrays are too error prone to be used in day to day tasks. Today's compilers are also very smart and can really produce excellent code with STL. If you know what you are doing, STL can usually provide the necessary performance. For example by initializing vectors to required size (if you know from start), you can basically achieve the array performance. However, there might be cases where you still need arrays. When interfacing with low level code (i.e. assembly) or old libraries that require arrays, you might not be able to use vectors.

Chthonian answered 19/12, 2008 at 17:37 Comment(6)
given that vector is contiguous, it is still pretty easy to interface with libraries that require arrays.Sensitive
Yes, but if you want to mess with vector's internal stuff, there would be less advantage in using a vector. By the way, the keyword was "might not."Chthonian
there is only one case i know of where vectors can't be used: if the size is 0. then &a[0] or &*a.begin() won't work. c++1x will fix that with introducing a a.data() function which returns the internal buffer keeping the elementsNarrowminded
The specific scenario in my mind when I wrote that was stack-based arrays.Chthonian
Interfacing vector or any contiguous container with C: vec.data() for data and vec.size() for size. It's that easy.Moxie
Not true nowadays. See Mike Acton's talk 'Data Oriented Design'Blavatsky
R
4

If you compile the software in debug mode, many compilers will not inline the accessor functions of the vector. This will make the stl vector implementation much slower in circumstances where performance is an issue. It will also make the code easier to debug since you can see in the debugger how much memory was allocated.

In optimized mode, I would expect the stl vector to approach the efficiency of an array. This is since many of the vector methods are now inlined.

Run answered 19/12, 2008 at 20:4 Comment(1)
This is important to mention. Profiling debug STL stuff is very, very slow. And it's one of the reasons why people thing STL is slow.Danieladaniele
C
3

The performance difference between the two is very much implementation dependent - if you compare a badly implemented std::vector to an optimal array implementation, the array would win, but turn it around and the vector would win...

As long as you compare apples with apples (either both the array and the vector have a fixed number of elements, or both get resized dynamically) I would think that the performance difference is negligible as long as you follow got STL coding practise. Don't forget that using standard C++ containers also allows you to make use of the pre-rolled algorithms that are part of the standard C++ library and most of them are likely to be better performing than the average implementation of the same algorithm you build yourself.

That said, IMHO the vector wins in a debug scenario with a debug STL as most STL implementations with a proper debug mode can at least highlight/cathc the typical mistakes made by people when working with standard containers.

Oh, and don't forget that the array and the vector share the same memory layout so you can use vectors to pass data to legacy C or C++ code that expects basic arrays. Keep in mind that most bets are off in that scenario, though, and you're dealing with raw memory again.

Cycle answered 19/12, 2008 at 17:45 Comment(3)
I think that to meet the performance requirements ( O(1) lookups and insertions ), you almost have to implement std::vector<> using dynamic arrays. Certainly this is the obvious way to do it.Sulphide
Not just the performance requirements, but also the requirement that storage in contiguous. A bad vector implementation will put too many layers of indirection between the array and the API. A good vector implementation will allow for inlined code, SIMD used on loops, etc.Cayenne
A bad vector implementation as described would not be compliant with the standard. If you want indirection, std::deque might be used.Emissary
H
2

The following simple test:

C++ Array vs Vector performance test explanation

contradicts the conclusions from "Comparison of assembly code generated for basic indexing, dereferencing, and increment operations on vectors and arrays/pointers."

There must be a difference between the arrays and vectors. The test says so... just try it, the code is there...

Hayes answered 14/4, 2013 at 6:31 Comment(1)
I did some benchmarking too as I was curious how these behaved on a microcontroller, the RP2040 Pi Pico with g++: Instructables: Benchmarking C++ Arrays on the Pi PicoOutstretched
Z
2

If you're using vectors to represent multi-dimensional behavior, there is a performance hit.

Do 2D+ (e.g., 3D) vectors cause a performance hit?

The gist is that there's a small amount of overhead with each sub-vector having size information, and there will not necessarily be serialization of data (as there is with multi-dimensional C arrays). This lack of serialization can offer greater than micro optimization opportunities. If you're doing multi-dimensional arrays, it may be best to just extend std::vector and roll your own get/set/resize bits function.

Zebu answered 3/3, 2019 at 21:58 Comment(0)
S
1

If you do not need to dynamically adjust the size, you have the memory overhead of saving the capacity (one pointer/size_t). That's it.

Sensitive answered 19/12, 2008 at 17:41 Comment(0)
G
1

There might be some edge case where you have a vector access inside an inline function inside an inline function, where you've gone beyond what the compiler will inline and it will force a function call. That would be so rare as to not be worth worrying about - in general I would agree with litb.

I'm surprised nobody has mentioned this yet - don't worry about performance until it has been proven to be a problem, then benchmark.

Governance answered 19/12, 2008 at 18:4 Comment(0)
D
1

Sometimes arrays are indeed better than vectors. If you are always manipulating a fixed length set of objects, arrays are better. Consider the following code snippets:

int main() {
    int v[3];
    v[0] = 1; v[1] = 2; v[2] = 3;
    int sum;
    int starttime = time(NULL);
    cout << starttime << endl;

    for (int i=0; i<50000; i++)
        for (int j=0; j<10000; j++) {
            X x(v);
            sum += x.first();
        }

    int endtime = time(NULL);
    cout << endtime << endl;
    cout << endtime - starttime << endl;
}

where the vector version of X is

class X {
    vector<int> vec;

    public:
        X(const vector<int>& v) {vec = v;}
        int first() { return vec[0];}
};

And the array version of X is:

class X {
    int f[3];

    public:
        X(int a[]) {f[0] = a[0]; f[1] = a[1]; f[2] = a[2];}
        int first() { return f[0];}
};

The array version will of main() will be faster, because we are avoiding the overhead of "new" everytime in the inner loop.

(This code was posted to comp.lang.c++ by me).

Dar answered 19/12, 2008 at 18:7 Comment(0)
K
1

I'd argue that the primary concern isn't performance, but safety. You can make a lot of mistakes with arrays (consider resizing, for example), where a vector would save you a lot of pain.

Kleenex answered 19/12, 2008 at 18:8 Comment(0)
C
1

Vectors use a tiny bit more memory than arrays since they contain the size of the array. They also increase the hard disk size of programs and probably the memory footprint of programs. These increases are tiny, but may matter if you're working with an embedded system. Though most places where these differences matter are places where you would use C rather than C++.

Cryohydrate answered 11/5, 2009 at 21:37 Comment(1)
If this matters, then you're obviously not using dynamically-sized arrays, and as such, your arrays don't need to change size. (If they did, you'd be storing the size somehow). Therefore, you might as well use boost::array unless I'm mistaken - and what makes you say that that needs to "store the size" somewhere?Exalt
C
1

For fixed-length arrays, the performance is the same (vs. vector<>) in release build, but in a debug build, low-level arrays win by a factor of 20 in my experience (Microsoft Visual Studio 2015, C++11).

So the "save time debugging" argument in favor of STL might be valid if you (or your coworkers) tend to introduce bugs in your array usage, but maybe not if your debugging time is mostly waiting on your code to run to the point you are currently working on so that you can step through it.

Experienced developers working on numerically intensive code sometimes fall into the second group (especially if they use vector :) ).

Chancechancel answered 25/3, 2021 at 7:11 Comment(0)
D
0

Assuming a fixed-length array (e.g. int* v = new int[1000]; vs std::vector<int> v(1000);, with the size of v being kept fixed at 1000), the only performance consideration that really matters (or at least mattered to me when I was in a similar dilemma) is the speed of access to an element. I looked up the STL's vector code, and here is what I found:

const_reference
operator[](size_type __n) const
{ return *(this->_M_impl._M_start + __n); }

This function will most certainly be inlined by the compiler. So, as long as the only thing that you plan to do with v is access its elements with operator[], it seems like there shouldn't really be any difference in performance.

Diastase answered 7/12, 2018 at 20:18 Comment(0)
D
0

I remember coming to this question a long time ago, thinking that C style arrays must surely be quicker than std::vector.

However, I read a lot of posts that said there wasn't any difference in performance or that difference was minuscule (where it really wouldn't matter) and therefore my premise was wrong.

One of the other lessons I took away was always to test/benchmark/profile and so I did do my own tests, like a few of the folks here have done, and I found that indeed C style arrays were faster than std::vector.

However, these tests were floored, because I didn't know about compiler optimisations. both clang++ and g++ have compiler optimisation flags, (-O0 being for debugging). With flag -O2, std::vector indeed became as fast as the C style array. I was indeed wrong. A few folks have said compiling without any flags is normal, but I'd disagree quite strongly with that statement. Using -O2 is commonplace along with many other flags, and in my experience perhaps using -O3 is unusual.

Using arrays or std::vectors in C++, what's the performance gap? There is little to no performance gap (if you're comparing like operation to like operation) if you use -O2 optimisation flag. However I'm sure it's possible engineer a scenario where there would be (a performance gap) if you know the compiler very well or are doing something out of the ordinary...

Dodger answered 30/4, 2023 at 1:29 Comment(1)
Optimisation flag -O3 isn't that unusual: pyenv builds parts of python using gcc, using flag -03: gcc -pthread -fPIC -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -std=c11 -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -Werror=implicit-function-declaration -fvisibility=hidden -I./Include/internal -I./Modules/_sqlite etc..Dodger
B
-1

There isn't any argument about which of them is the best or good to use. They both have there own use cases, and they both have their pros and cons.

The behavior of both containers are different in different places. One of the main difficulties with arrays is that they are fixed in size. If once they are defined or initialized, then you can not change values and on the other side, vectors are flexible; you can change vectors value whenever you want. It's not fixed in size like arrays, because an array has static memory allocation and vector has dynamic memory or heap memory allocation (we can push and pop elements into/from vector) and the creator of C++, Bjarne Stroustrup, said that vectors are flexible to use more than arrays:

Using C++ arrays with new (that is, using dynamic arrays) should be avoided. There is the problem you have to keep track of the size, and you need to delete them manually and do all sort of housekeeping.

We can also insert, push and pull values easily in vectors which is not easily possible in arrays.

If we talk about performance-wise then if you are working with small values then you should use arrays and if you are working with big scale code then you should go with vector (vectors are better at handling big values than arrays).

Bedroom answered 12/9, 2022 at 11:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.