繁体   English   中英

带有std :: vector的指针算术

[英]Pointer arithmetic with std::vector

以前,我正在使用具有接口的库中的一些代码

void f( T* x );
void g( T* x );

哪里

  • f将用一些值填充x的前m个条目(覆盖x任何值)
  • g将用一些值填充x的前n个条目(覆盖x任何值)

我想将这两个值连接起来,所以我这样做了

void concat( T* x ){
    f(x);
    x += m; 
    g(x);
    x += n; 
    ...
}

实际上,大约有10个这样的函数是我使用指针运算法则进行连接的。

现在,我们正试图将不同的库用于相同的目的。 但是,新库具有接口

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

同样,这些函数分别填充x的前mn元素(覆盖x当前存在的任何内容)。 此外,我必须使用签名创建一个新的concat函数

void concat_new( std::vector<T> & x  ){
    // TODO
    ...
}

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

注意:我不能修改concat_new,f_new或g_new的签名

没有有效的方法来执行此操作。

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

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

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您至少可以跳过重新分配。


如果可以更改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足够大!

继续使用旧的fg ,它们比f_newg_new更适合您。

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

请图书馆的作者采用@bartop的签名 (也许是重载)

我认为,与传递整个std :: vectors相比,vector的迭代器足以完成您的任务。 它为您提供与指针完全相同的功能,并且可以与vector一起使用。 我会选择这样的东西:

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

最重要的是-如果您在代码中没有邪恶的指针法术,则无需对代码进行任何进一步的更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM