Previously, I was working with some code in a library that had the interface
void f( T* x );
void g( T* x );
where
f
would fill the first m
entries of x
with some values (overwriting whatever is in x
) g
would fill the first n
entries of x
with some values (overwriting whatever is in x
) I wanted to concatenate these two values, so I did this
void concat( T* x ){
f(x);
x += m;
g(x);
x += n;
...
}
Actually, there were about 10 such functions that I concatenated using pointer arithmetic like this.
Now we are trying to use a different library for the same purpose. However, the new library has the interface
void f_new( std::vector<T> & x );
void g_new( std::vector<T> & x );
where again, these functions fill the first m
and n
elements of x
, respectively, (overwriting whatever is currently in x
). Furthermore, I must create a new concat
function with the signature
void concat_new( std::vector<T> & x ){
// TODO
...
}
What is the most efficient way of achieving the previous result with vectors? The only way I can figure out how to do this is by copying data between calls.
NOTE: I can't modify the signatures for concat_new, f_new, or g_new
There is no efficient way of doing this.
A good library should use iterators. If it does not you will have to copy the elements.
However: You can optimize a bit by reserving space for the target vector if you know the final size.
void concat( std::vector<T>& x ){
x.reserve(m+n+...);
f(x);
std::vector<T> buffer;
buffer.reserve(std::max({n, ...}));
g(buffer);
x.insert(x.end(), buffer.begin(), buffer.end());
...
}
by reusing buffer
you can at least skip the reallocations.
IF you could change the signature of f then change it to
void f(std::vector<T>::iterator begin, std::vector<T>::iterator end) {
... // (should use 'end' at least to check the target size)
}
You can always use a wrapper for backward compatibility:
void f(std::vector<T>& x)
{
f(x.begin(), x.end());
}
Then use
void concat( std::vector<T>& x) {
assert(x.size() >= m+n);
f(x.begin(), x.begin() + m);
g(x.begin() + m, x.begin() + m + n);
}
But make sure x is large enough!
Carry on using the old f
and g
, they are more applicable to you than f_new
and g_new
.
void concat_new( std::vector<T> & x )
{
auto it = x.data();
f(it);
it += m;
g(it);
it += n;
...
}
Petition the author of the library to adopt @bartop's signatures (as an overload, perhaps)
I think that instead of passing whole std::vectors, the vector's iterator would be sufficient for Your task. It gives You exactly the same functionallity as the pointer and works with vector. I'd go with something like this:
void concat_new( std::vector<T> & x ){
auto it = x.begin();
f(x);
it += m;
g(x);
it += n;
...
}
With it, f and g would be like this:
void f_new( std::vector<T>::iterator x );
void g_new( std::vector<T>::iterator x );
The thing that is great about it - You would not need any further changes in code if You did no evil pointer sorcery in the code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.