Reputation: 3714
I'd like to resize a std::vector< std::vector< T > > to a known size (m, n) as efficiently as possible, ideally without any memory copying (T is float or double).
class Foo {
std::vector< std::vector< T > > data;
std::vector< std::vector< T > > data_norm;
std::vector< T > min_values;
std::vector< T > max_values;
void normalize();
}
data is filled dynamically, pushing_back new data one 'row' at a time. Each 'row' is guaranteed to have the same number of elements. So it is effectively an m x n table.
Then at one point I call the normalize() method which:
Currently I'm doing data_norm = data at the start of my normalize() method just to make sure data_norm is allocated to the right size and there are no further re-allocations. But that involves copying all of the memory. Is there a way to do it without this memory copy?
I've seen this post which suggests
std::vector<std::vector<T>> my_vec(m, std::vector<T>(n))
However in my situation my_vec already exists. I could create and assign a new_vec:
std::vector<std::vector<T>> new_vec(m, std::vector<T>(n));
data_norm = new_vec;
But I guess that's still going to have the memory copy, in fact it'll be slower than data_norm = data because a whole new vector (new_vec) is initialized and allocated, and I already have a source vector of the right size.
I was hoping there is a way of doing it with a resize-like method? But without iterating through and doing resize on each sub-vector - which would create crazy reallocations I guess.
Upvotes: 1
Views: 2104
Reputation: 88155
Currently I'm doing data_norm = data at the start of my normalize() method just to make sure data_norm is allocated to the right size and there are no further re-allocations.
First, you should simply design your program such that nobody can resize the vectors and ensure that you're not resizing them and then you can avoid this work entirely. You could put some asserts in your code to make sure the size never changes in debug mode if you want to be extra safe.
Also, if you want to do the work 'as efficiently as possible', then you should avoid using a vector of vectors, since for a rectangular matrix that's more allocations than necessary.
There's currently no standard container that provides an efficient multi-dimensional array with runtime bounds, but you can pretty easily define one. Here's a pretty minimal example.
template<typename T>
class vector2d {
std::vector<T> data;
int columns;
public:
struct index { int r, c; };
vector2d(index i) : data(i.r * i.c), columns(i.c) {}
T &operator[] (index i) { return data[i.r*columns + i.c]; }
}
And then you can write:
class Foo {
vector2d<T> data;
vector2d<T> data_norm;
std::vector<T> min_values;
std::vector<T> max_values;
void normalize();
Foo(int n, int m) : data({n, m}), data_norm({n, m}) {}
}
And if you want to do the same thing for an arbitrary number of dimensions that can be done as well.
Upvotes: 1
Reputation: 480
You can use vector::resize()
, it does it without creating a temporary vector
http://www.cplusplus.com/reference/vector/vector/resize/
// resizing vector
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector;
// set some initial content:
for (int i=1;i<10;i++) myvector.push_back(i);
myvector.resize(5);
myvector.resize(8,100);
myvector.resize(12);
std::cout << "myvector contains:";
for (int i=0;i<myvector.size();i++)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
Output:
myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0
Upvotes: 2