tags:

views:

319

answers:

11

I have a vector declared as a global variable that I need to be able to reuse. For example, I am reading multiple files of data, parsing the data to create objects that are then stored in a vector.

vector<Object> objVector(100);

void main()
{
 while(THERE_ARE_MORE_FILES_TO_READ)
 {
    // Pseudocode
     ReadFile();
     ParseFileIntoVector();
     ProcessObjectsInVector();
     /* Here I want to 'reset' the vector to 100 empty objects again */

 }

}

Can I reset the vector to be "vector objVector(100)" since it was initially allocated on the stack? If I do "objVector.clear()", it removes all 100 objects and I would have a vector with a size of 0. I need it to be a size of 100 at the start of every loop.

+1  A: 

Call resize at the beginning or end of the loop: http://www.cplusplus.com/reference/stl/vector/resize/

That should do what you want. However, I would recommend using the push and pop functions instead. It is more space efficient and is how the Vector was intended to be used. The vector will expand and shrink as needed when you push (add) and pop (remove) items from it. That way you don't have to worry about the vector's size or contents. It simply becomes a processing queue.

Daniel Bingham
A: 

Are you sure you want the size 100? Not just the capacity?

Let_Me_Be
+1  A: 

The following code should do the trick.

vector<Object> temp(100);
objVector.swap(temp);
Findekano
That doesn't help much since you just discard a different vector, but you still do discard it.
Let_Me_Be
@Let_Me_Be: This discards what you already had, replacing it with 100 default-constructed Objects - what the OP asked for.
UncleBens
@Let_Me_Be: I actually not quite understand your comment. Could you please clarify a bit?
Findekano
I think I misunderstood. I thought that he wants a speed optimization (no memory allocation/deallocation), but it doesn't seem to be the case.
Let_Me_Be
Yes, it probably wouldn't be the fastest way. Swapping with temporaries is generally used to implement "shrink (capacity) to fit".
UncleBens
+2  A: 
vector<Object> objVector(100); 

int main() 
{ 
 while(THERE_ARE_MORE_FILES_TO_READ) 
 { 
    // Pseudocode 
     ReadFile(); 
     ParseFileIntoVector(); 
     ProcessObjectsInVector(); 
     /* Here I want to 'reset' the vector to 100 empty objects again */ 
     objVector.clear();
     objVector.resize(100);

 } 
}
TheMachineCharmer
That did it. Thanks!
Bobby
Well, I still think swap() is the recommend way to do this kind of job. See Item 17 of Effective STL: Use “the swap trick” to trim excess capacity. do a clear and then resize is actually slower - it has extra memory allocation operations than the swap()
Findekano
Trimming the excess capacity is most often not desired (that's why stdlib doesn't do it either). There is a performance hit caused by frequent allocations. The performance benefit looked for by reusing the vector would be entirely lost, too.
Tronic
As you say, the swap trick trims excess capacity - which there doesn't appear to be in this case.
Joe Gauterin
+6  A: 
objVector.clear();
objVector.resize(100);

However, this is probably not recommended usage of vector. Are you quite sure you shouldn't be using push_back with a vector that is initially empty? How can you be sure that each file contains exactly 100 Objects, no more no less, as it appears from your question?

The vector probably doesn't need to be global either. Better to pass things around. When you see a bunch of functions called with no parameters, it is quite hard if not impossible to follow what is going on (because everyone else other than you - and including you when you come back to this code after a few months - will have no idea what these functions use for input and what is the output).

UncleBens
A: 

Call objVector.clear() to remove previous data points, and then objVector.resize(100) to resize it to the appropriate size.

Note, though, that this is going to allocate 1 instance of Object using the default constructor, and then 100 copies of Object using the copy constructor, which may or may not be what you actually want. Optionally, if Object is a pointer type, you can use objVector.resize(100, NULL) to avoid possibly-unwanted allocations.

Dathan
No unwanted allocation will take place if `Object` is a pointer type, passing `NULL` to `resize` is completely redundant, since the same would happen without it.
Konrad Rudolph
Also, you assertion about the copy constructor is wrong. The default constructor would be called each time, i.e. 100 times.
Konrad Rudolph
@Konrad you're mistaken on the second point. The default may be called 100 times in the case of the class having only implicit constructors, but a quick test app will show that the copy constructor is indeed called if implemented. However, I was mistaken: the default constructor is called once, and the copy constructor is called 100 times, not 99.
Dathan
@Dathan: you’re right of course, stupid mistake. As I’ve said myself, calling `resize(n)` is the same as calling `resize(n, T())` so *of course* it’s the copy constructor that gets called, not the constructor itself. Duh.
Konrad Rudolph
+9  A: 

I have a vector declared as a global variable that I need to be able to reuse.

Why? It’s not clear from your code why the variable must be global. Why can’t you declare it inside the loop? Then you don’t need to reset it, this will be done automatically in each loop.

In order to access the variable from the other methods, pass it in as a parameter (by reference, so you can modify it). Having a global variable is rarely a good solution.

Something else: main must never have return type void, this is invalid C++ and many compilers will reject it.

Konrad Rudolph
A: 

Since you are using the default constructor for "Object", I think you should be able to rely on the vector's capacity instead of its size. So, when you call clear(), chances are you are not changing the capacity that was set by your vector constructor (you can hold at least 100 elements, they are already allocated). Read up on capacity, reserve, and size and how they each differ (reserve is the call you'd make to request changes of capacity, I'm just pointing it out in case you need it).

Anyway, though, if you need to reset your objects to the default state, rather than relying on the ability to do a vector-wide reset of the objects, you could also just make a call on your object called "reset" to set them to that state, and call it before you re-process using those same objects. Performance-wise, I don't see it as being any different, and code-wise it seems like a clean solution.

RobK
+1  A: 

Contrary to the other posts, the most efficient way to do this is probably this:

objVector.resize(0);
objVector.resize(100);

clear() frees the memory of the vector on some implementations (its only required postcondition is that size()=0). resize(0) maintains the capacity.

The swap trick also invokes an unecessary memory allocation. The temporary vector which you swap will allocate a new memory block, and after the swap the old memory block is released as well. Performance should be better without memory allocations.

AshleysBrain
Actually, i looked it up. While in C++03 both `.clear()` and `.resize(0)` couldn't cause a reallocation (because that would have invalidated `.begin()`, which C++03 did not allow), C++0x seems to allow both `.clear()` and `.resize(0)` to reallocate (since they may now invalidate `.begin()`). Of course, a reallocation doesn't imply a change of the capacity, so one can't argue that like "since the capacity won't change, no reallocation happens.", i think.
Johannes Schaub - litb
The silent change that made `.resize(0)` and `.clear()` possibly reallocate is this one: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#414 (notice that both still must reallocate to the same or larger amount of memory as stored in the capacity. So it would be rather pointless for them to reallocate. But theoretically, they may, if i read this correctly).
Johannes Schaub - litb
Heh, this turned out to be more complicated than I thought. Thanks for the comments.
AshleysBrain
+2  A: 

Why are you trying to reset a global variable? Just allocate a new vector each time through the loop, and pass the vector into the functions by reference.

void ParseFileIntoVector(vector<Object> &vector);
void ProcessObjectsInVector(const vector<Object> &vector);

int main() 
{ 
 while(THERE_ARE_MORE_FILES_TO_READ) 
 { 
     // Pseudocode 
     vector<Object> objVector(100); 
     ReadFile(); 
     ParseFileIntoVector(objVector); 
     ProcessObjectsInVector(objVector); 
 } 
}
Eclipse
A: 
Can I reset the vector to be "vector objVector(100)" since it was initially allocated on the stack?
  1. The C++ vectors are not allocated on stack. At least not directly. One of the parameters to vector (and other STL templates) is allocator. You can use pool allocators, heap allocators etc.

    The std::vector<T> is in fact nicely packed pointer to array with additional informations (such as size and capacity). Otherwise the size of vector had to be known in advance (which is not required).

  2. In fact in the example above the std::vector<T> is not on stack but in data section of program (or how is it called on non-ELF platforms).

So the question is if you need:

  • A vector of size 100. In this case, as it have been pointed out, it is likely that you are doing something strange. But it is still possible in nice way by resize method.
  • A vector of capacity 100. In this case you probably should not do anything as vectors do not shrink its capacity AFAIR. And for sure it is not required as vectors changes its capacity dynamically.
Maciej Piechotka