span的正确性
span是具有引用语义的视图。从这个意义上讲,它们的行为类似于指针:当一个span为const时,并不自动意味着该span引用的元素是const。
这意味着您可以对const span的元素进行写访问(前提是这些元素不是const)。
std::array a1{1,2,3,4,5,6,7,8,9,10};
std::array a2{0, 8, 15};
const std::span<int> sp1{a1};
std::span<const int> sp2{a1};
sp1[0]=42;
sp2[0]=42;
sp1=a2;
sp2=a2;
注意,只要std::span<>
的元素没有被声明为const,就会有一些操作提供对元素的写访问,即使对于const span(遵循普通容器的规则)也是如此。
·operator[],first(),last()
·data()
·begin(),end(),rbegin(),rend()
·std::cbegin(),std::cend(),std::crbegin(),std::crend()
· std::ranges::cbegin(), std: :ranges: :cend(), std::ranges::crbegin(),std::ranges::crend()
是的,所有被设计为确保元素为const的c*函数都被std::span破坏。例如
template<typename T>
void modifyElems0fConstCollection (const T& coll)
{
co11[0] = {};
auto ptr = coll.data();
*ptr={};
for (auto pos= std::cbegin(col1); pos != std::cend(coll); ++pos) {
*pos={};
}
}
std::array a1{1,2,3,4,5,6,7,8,9,10};
modifyElems0fConstCollection(a1);
modifyElems0fConstCollection(std::span{a1});
这里的问题不是std::span
被破坏了;问题是像std:: cbegin()
和std::ranges::cbegin()
这样的函数目前对于具有引用语义的集合(例如视图)是被破坏的。
为确保函数只接受不能以这种方式修改元素的序列,可以要求const容器的begin()
返回指向const元素的迭代器
template<typename T>
void ensureRead0nlyElemAccess (const T& coll)
requires std::is_const_v<std::remove_reference_t<decltype(*col1.begin())>> {
...
}
至少,在标准化 C + + 20之后,甚至 std: : cstart ()
也提供了写访问。
提供 cstart ()
和 cend ()
的全部目的是确保在迭代元素时不能修改元素。
最初,span 确实为 const _ iterator
、 cstart ()
和 cend ()
类型提供了成员,以确保不能修改元素。然而,结果是 std: : cstart ()
仍然迭代可变元素(std: : range: : cstart ()
也有同样的问题)。
但是,没有修复 std: : cstart ()
(和 std: : range: : cstart ()
) ,而是删除了 span 中 const 迭代器的成员,这使问题变得更糟,因为现在已经没有简单的方法可以在 span 中进行只读迭代。
修复该问题的正确方法是修复 std: : cbegin ()
的定义方式
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 N 天,点击查看活动详情”