因此,如果你想共享shared_ptr
过去元素x
中的所有内容,你可以写如下代码:
int main(){
std::shared_ptr<float[]> _vals = std::make_unique<float[]>(70);
for(uint32_t i = 0; i < 10; ++i)
_vals[i] = i;
//range from 2 - end of _vals
// x = 2 in this case
std::shared_ptr<float[]> _partial(_vals, &_vals[2]);
for(uint32_t i = 0; i < 5; ++i)
std::cout<<_partial[i]<<" ";
std::cout<<std::endl;
return 0;
}
字符串
所以输出将是:
2 3 4 5 6
型
所以_partial
将从_vals.get() + 2
指向_vals
的末尾。但是,如果我想让它指向例如(2-5), (70-end)
,我想知道我是否可以为_partial
分配地址来完成这一点呢?例如,如果这起作用:
int main(){
std::shared_ptr<float[]> _vals = std::make_unique<float[]>(70);
for(uint32_t i = 0; i < 70; ++i)
_vals[i] = i;
//range from 2 - 5, and then range from 70-73
std::shared_ptr<float[]> _partial(_vals, &_vals[2]);
float** begin = &(&_vals[70]);
float** end = &(&_vals[73]);
float** beg_2 = &(&_partial[2]);
for(;begin != end; ++(*begin), ++(*beg_2)){
beg_2 = begin;
}
//so technically _partial[0] would point to _vals[2] but _partial[3] would point to _vals[70]
for(uint32_t i = 0; i < 5; ++i)
std::cout<<_partial[i]<<" ";
std::cout<<std::endl;
return 0;
}
型
但是,如果我尝试编译它,我会得到错误:
cannot take the address of an rvalue of type 'float *'
float** begin = &(&_vals[70]);
型
有没有一种方法可以完成我正在努力做的事情?
4条答案
按热度按时间krcsximq1#
shared_ptr
不适合这项工作。一个shared_ptr
拥有某个对象并指向某个(可能不同的)对象。它 * 没有 * 实现足够的逻辑来执行0 -> 0, 1 -> 1, 2 -> 2, 3 -> 70
之类的Map。(它也不应执行这一逻辑。这不是一项简单的任务。)实现您自己的类以实现此行为。这应该可以帮助您开始:
字符串
vyu0f0g12#
如果分散跨度需要原始数组的共享指针,则可以在共享指针对中捕获该信息,然后将其放入这些对的向量中。
我冒昧地将原始数组设为99个元素,因此第二个跨度将是有效的。
字符串
c86crjj03#
智能指针都是关于所有权的--谁拥有你分配的那块内存?你不能让一个智能指针拥有整个数组,而另一个只拥有其中的一部分,这在物理上是不可能的。
t5zmwmid4#
所以
_partial
将从_vals.get() + 2
指向_vals
的末尾。不可以。指针指向单个对象,而不是一个范围。在本例中,
_partial
指向_vals.get() + 2
。只有一个元素。这样就可以访问_vals
的某个子范围的想法是基于您对如何访问元素所采用的约定。举个例子:你的循环打印了
_vals
的第三到第七个元素。您的文本建议循环应该“到_vals
的末尾”(第70个元素),但它没有。为什么?因为你的循环结束于索引5而不是68。这不是_partial
固有的,而是您如何使用_partial
的结果。类似地,循环从索引0(
_partial
的索引)开始。这是你的选择虽然从索引0开始是常规的,但它仅仅是常规的。在您的特定情况下,_partial
指向数组的第三个元素。这意味着表达式_partial.get()[-2]
是法律的的,并且指向数组的第一个元素。(表达式_partial[-2]
在实践中可能也适用,但cppreference.com说该行为是未定义的。)您的起点,就像您的终点一样,不是_partial
固有的东西,而是您如何使用_partial
的结果。结果是,你想要的行为不是关于所有权,而是关于如何使用你所拥有的数据。
重新构建问题
因此,我们可以从您的问题中删除共享所有权。你有一个数组,你需要一种方法来迭代数组的子范围。阵列的所有方式无关紧要;该问题仅需要存在数组和指定子范围的方式。
简单的情况是当子范围是连续的时。在这种情况下,子范围可以由其开始和结束来指定。一种常见的方法是提供一个指向开始的指针(
_partial
)和一个大小(5
,如果我们按照你的循环,或者68
,如果我们按照“_vals
的结尾”)。你知道怎么做。你的问题是如何指定一个不连续的子范围。非连续范围所面临的问题是
std::shared_ptr::operator[]
和内置的[]
运算符是为连续范围设计的。对象_partial[2]
和_partial[3]
必须位于相邻的内存位置。这就是这个操作员的工作方式。答案
那么我们能做些什么呢?在C17中,你可以写一个适配器类。这样一个类可以 Package 一个数组并提供一个
operator[]
来执行您想要的操作。也就是说,它将具有用于阵列访问的数据成员(例如,你的std::shared_ptr<float[]>
),它会以某种方式存储你想要访问的索引。我将把细节留给读者(或其他答案),因为这个答案花了很长时间才达到这一点。虽然这个问题被标记为C17,但我会注意到在C++20中,有范围。特别是,filter view可以用来选择您想要的底层视图的元素。例如,您可以为过滤器视图提供一个 predicate ,当参数minus
_vals
的地址介于2和5之间或介于60和65之间时,该 predicate 通过(返回true
)。我将把细节留给读者,因为这个问题要求20岁以前的答案。