tags:

views:

97

answers:

6

Hello everybody,

I would like to know the best solution in terms of performances for storing vectors/arrays of data (int or double), whose dimension is not available at compile time (it depends on the input from the user) but, once intialized, they will never change their dimensions, neither their values. In other words I was wondering if using something different than vector I can improve the efficiency, since I am sure that dimensions and content of my vector never change after initialization. Thanks Alberto

+2  A: 

Well, if you don't change the size of the vector, then you will not have the overhead of the realocation. So vector is still a good choice. If the data is not going to change either, you could use a const vector

Armen Tsirunyan
A: 

Use them in lists of integer/double, an example is shown here.

Jeff Norman
That example is quite ugly. Bad indentation, no comments, `.h` headers, dangerous default copy constructor and `operator=`, calls "list" an array, does not overload `operator[]` and doesn't even let the caller work with the stored objects, mixes container-logic with UI logic...
Matteo Italia
It was just an idea :), I didn't gave the example to copy-paste it in the code, I gave it for making an idea and think about it
Jeff Norman
I perfectly understand that, but if you provide an example, it's ok that it should show just the basic concepts, but it shouldn't be filled with errors and bad practices :)
Matteo Italia
+5  A: 

Despite the suspicions hinted in the question, I would still try to use std::vector (until proven otherwise) and invoke the member function reserve() to allocate space for all the elements as soon as I know the dimension from the user input. Calling reserve() upfront avoids repeated memory allocation and copying of elements.

ArunSaha
I agree, but if the size is truly fixed you might want to call "resize" instead of "reserve". then you can work with each element and never call "push_back".
edA-qa mort-ora-y
@edA-qa mort-ora-y: IIRC, `resize()` would call the default constructor of the elements, but `reserve()` won't. In this particular case, where elements are `int` or `double`, it may not matter, but I think that is a good practice. Moreover, after `reserve()` is called appropriately, `push_back()` is equivalent to array indexing `vec[ i ] = new_elem`.
ArunSaha
@ArunSaha: No, `push_back(x)` is not equivalent to `vec[i] = x`. It's invalid to use an index beyond the *size* of the array, even if it is within the *capacity*.
Mike Seymour
@Mike Seymour: You are right, but I did not say what `i` is :). It could be the incremented size. What I wanted to convey in the comment is that if `reserve()` is called appropriately, then `push_back`s would never invoke memory allocation and copying, they would be "equivalent" to assignments to array elements.
ArunSaha
If you do "resize" up-front you don't have any performance cost later. The standard is really missing a "resize_no_init" function; that'd often be the best option.
edA-qa mort-ora-y
+1  A: 

std::vector is fine. If you try to do math with the numbers in there std::valarray might be a good choice. It also can be modified and resized, but as long as you don’t use it an implementation should produce no overhead for this.

Sven
+1  A: 

If the size and contents truly never change after initialization, then use a const vector. If the contents are at all interesting, though, this means you'll have to use either the copy-constructor, or the constructor that takes an iterator pair.

It's unlikely to enable much in the way of optimization, but it's worth a try[*]. It forces your code to be const-correct, though, which is to say that not only must you not modify the vector, your code must constitute a particular kind of proof to the compiler that (barring unwise casts) you do not modify the vector.

That's extra work, if your code is not const-correct already, but as you go along the compiler will tell you what needs changing.

[*] By which I suppose I mean, as a general practice, it's worth using const where possible. The reasons for that don't have much to do with performance, though. If you're just looking to speed up a particular program, there are more effective uses of developer time than overhauling code that isn't const-correct, to be const-correct. But assuming it compiles, it's no effort to make the change.

Steve Jessop
A: 

Your alternative option is boost::shared_array. They are also reference-counted so you can copy a shared_array around without copying the data.

shared_array is limited: you cannot get the size out of it, nor const-protect your data by passing shared_array on it.

So to do that you would have to write a wrapper that can do both of these. If you are going to write a wrapper anyway you might just wrap shared_ptr > but that means more allocations and more indirection, so shared_array might be your friend.

shared_array is not part of tr1.

To use shared_array, you allocate the data the "old" way, i.e. with new T[N] when you want the data, but shared_array protects the lifetime of it so you don't have to worry about deleting it (as long as you don't make circular references).

CashCow