是否可以将向量的一部分作为向量发送给函数? [复制]
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])
【问题讨论】:
通常使用迭代器范围来完成(参见<algorithm>
中的函数)
可以发送一对迭代器。
发送两个迭代器是 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 中所述,<algorithm>
有很多这种模式的示例。
std::distance(first, last);
将返回所需的更改大小。如果不制作实体副本,我认为您无法更接近满足您的要求。
【讨论】:
我知道,但我想知道是否可以只使用一个参数 我对此表示怀疑,并想知道这如何使它更有效。我想必须发生一些转变,而您想避免这种情况。 @A.Mashreghi 是的,使用std::pair<std::vector<int>::iterator,std::vector<int>::iterator>
。【参考方案2】:
如果你有一个包含 100 个元素的向量
std::vector<int> v(100);
如果你想用前 10 个元素调用void f(std::vector<int> 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)
中不可能发生的副本以上是关于是否可以将向量的一部分作为向量发送给函数? [复制]的主要内容,如果未能解决你的问题,请参考以下文章