是否可以将向量的一部分作为向量发送给函数? [复制]

Posted

技术标签:

【中文标题】是否可以将向量的一部分作为向量发送给函数? [复制]【英文标题】:Is it possible to send part of vector as a vector to a function? [duplicate] 【发布时间】:2017-10-28 05:10:51 【问题描述】:

我想看看是否可以将向量的一部分传递给函数,使其显示为函数的法线向量。更重要的是,我希望这在 O(1) 恒定时间内完成。我不想迭代向量来制作一个新的。其实下例中我也想让新向量的大小变成40。

void func(vector <int> &v)

    //calling index 10  to 50 of v
    func(v[10..50])

【问题讨论】:

通常使用迭代器范围来完成(参见&lt;algorithm&gt;中的函数) 可以发送一对迭代器。 发送两个迭代器是 C++ 的惯用方式。 迭代器作为函数参数不是线程安全的。而是发送向量,上下限,使用互斥锁来保护向量。 @ark1974 这有点牵强。 【参考方案1】:

使用迭代器作为基于范围的函数的参数,并传入所需的范围。你在函数中的代码变成了

funcWithRange(v.cbegin()+10, v.cbegin()+50);

带有函数签名

void funcWithRange(std::vector<int>::const_iterator first, std::vector<int>::const_iterator last)

这可以通过将其作为具有vector 成员类型作为其模板参数的函数模板来概括,或者更进一步到任何支持这种类型范围迭代的容器。正如 cmets 中所述,&lt;algorithm&gt; 有很多这种模式的示例。

std::distance(first, last); 将返回所需的更改大小。如果不制作实体副本,我认为您无法更接近满足您的要求。

【讨论】:

我知道,但我想知道是否可以只使用一个参数 我对此表示怀疑,并想知道这如何使它更有效。我想必须发生一些转变,而您想避免这种情况。 @A.Mashreghi 是的,使用std::pair&lt;std::vector&lt;int&gt;::iterator,std::vector&lt;int&gt;::iterator&gt;【参考方案2】:

如果你有一个包含 100 个元素的向量

std::vector<int> v(100);

如果你想用前 10 个元素调用void f(std::vector&lt;int&gt; v),只需调用函数为

f(v.cbegin(), v.cbegin() + 10);

这将从两个迭代器构造一个新向量(通过复制元素)并将新向量传递给f

【讨论】:

这个方案有个缺点,就是函数不再作用于原始向量。 这真的很有趣,但这是否复制了向量?我不认为它在恒定时间内工作,与范围的长度无关。 @A.Mashreghi 是的,这是复制以创建新向量。如果你需要一个新的向量,你不能避免复制。这就是为什么在 C++ 中如此多地使用迭代器的原因。您需要重新考虑您的要求。 @A.Mashreghi 是的,这将创建子部分的副本。 @πάντα ῥεῖ 是真的。我只是想把它作为一种选择。 A. Mashreghi 是的,它是复制品。【参考方案3】:

有一种方法可以实现与此类似的东西,该方法被提议包含在C++ 标准中。它被称为span,在某些方面它的操作类似于向量。

#include <gsl/span>

void func(gsl::span<int> sp)

    for(auto& i: sp)
        std::cout << i << '\n';


int main()

    // ...

    std::vector<int> v(100);

    // put something in the vector (numbers 0 - 99)
    std::iota(std::begin(v), std::end(v), 0);

    // wrap the container in a span
    auto sp = gsl::make_span(v);

    // send parts of it to functions
    func(sp.subspan(10, 50));

span 在原始向量上显示一个窗口,因此它是一个引用类型。它不包含自己的数据,只是指向向量中数据的指针。因此,它们是轻量级的,旨在按值传递。

span 的实现可以在这里找到:https://github.com/Microsoft/GSL

这是 Bjarne Stroustrup 和 Herb Sutter 编写的最佳实践指南中推荐的传递连续容器的方法。

可在此处找到指南:CppCoreGuidelines.md

【讨论】:

两个迭代器的std::pair有什么区别? @πάνταῥεῖ span 进行了边界检查,API 应该更健壮,因此很难获得越界范围。越界执行v.begin() + 50 不会触发异常,它会悄悄地执行未定义的行为。但是sp.subspan(0, 50)会被检查。 @Galik 如果我操纵传递给 func 的子跨度,那会改变 sp 中的原始值吗?我的意思是这是副本还是对原件的引用? @A.Mashreghi 是参考,原来的向量发生了变化 @A.Mashreghi 否则你将不得不制作一个在O(1)中不可能发生的副本

以上是关于是否可以将向量的一部分作为向量发送给函数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何将向量的一部分作为函数参数传递?

如何将向量传递给函数?

C++11 线程:将向量传递给线程函数时出错

如何通过将向量元素传递给函数来更改它们

扩展作为内存传递的向量的大小

将向量作为对递归函数的引用传递