使用std :: vector的指针算术

时间:2018-04-17 08:53:28

标签: c++

以前,我正在使用具有接口

的库中的一些代码
void f( T* x );
void g( T* x );

其中

  • f会将m的{​​{1}}个条目填入一些值(覆盖x中的任何内容)
  • x会将g的{​​{1}}个条目填入一些值(覆盖n中的任何内容)

我想连接这两个值,所以我做了这个

x

实际上,我使用像这样的指针算法连接了大约10个这样的函数。

现在我们正在尝试使用不同的库来达到同样的目的。但是,新库具有接口

x

同样,这些函数分别填充void concat( T* x ){ f(x); x += m; g(x); x += n; ... } 的第一个void f_new( std::vector<T> & x ); void g_new( std::vector<T> & x ); m元素(覆盖当前n中的任何内容)。此外,我必须使用签名

创建一个新的x函数
x

使用向量实现先前结果的最有效方法是什么? 我能弄清楚如何做到这一点的唯一方法是在调用之间复制数据。

注意:我无法修改concat_new,f_new或g_new的签名

3 个答案:

答案 0 :(得分:2)

没有有效的方法可以做到这一点。

一个好的库应该使用迭代器。如果不是,则必须复制元素。

但是:如果您知道最终大小,则可以通过为目标向量保留空间来优化位。

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());

    ...
}

通过重用buffer,您至少可以跳过重新分配。

IF 您可以更改f的签名然后将其更改为

void f(std::vector<T>::iterator begin, std::vector<T>::iterator end) {
  ... // (should use 'end' at least to check the target size)
}

您始终可以使用包装器来实现向后兼容:

void f(std::vector<T>& x)
{ 
  f(x.begin(), x.end());
}

然后使用

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);
}

但请确保x足够大!

答案 1 :(得分:0)

继续使用旧版fg,它们比f_newg_new更适用于您。

void concat_new( std::vector<T> & x  )
{
    auto it = x.data();
    f(it);
    it += m; 
    g(it);
    it += n; 
    ...
}

请求图书馆的作者采用@bartop's signatures(也许是过载)

答案 2 :(得分:-1)

我认为不是传递整个std :: vectors,而是向量的迭代器就足以完成你的任务了。它为您提供与指针完全相同的功能,并与向量一起使用。我会选择这样的东西:

void concat_new( std::vector<T> & x  ){
    auto it = x.begin();
    f(x);
    it += m; 
    g(x);
    it += n; 
    ...
}

有了它,f和g会是这样的:

void f_new( std::vector<T>::iterator x );
void g_new( std::vector<T>::iterator x );

关于它的好处 - 如果您在代码中没有使用邪恶的指针法术,则不需要对代码进行任何进一步的更改。