dan*_*ani 16 c++ pointers vector
我有一个std::vector<int>指针指向int*向量中的元素.假设指针指向第三个元素:pointer=&vector.at(2).如果我现在对矢量进行混洗,它是否仍然指向相同的元素(第三个),还是它指向新的位置,而这个元素曾经是第三个元素现在已经移动了?
在那之后,我想让问题更加通用:当向量扩展或缩小时,向量中元素的指针和迭代器如何表现?
Jer*_*fin 17
指针将继续指向同一位置,因此当您进行随机播放时,它将指向已移动到您指定位置的任何元素.
展开向量的大小时,向量中的所有现有指针和迭代器都可能变为无效.当你洗牌时,他们会继续引用相同的位置,这通常会包含与改组前不同的值.
减小矢量的大小将取决于您如何做到这一点.一种方法是创建一个临时向量作为当前向量的副本,交换两个,然后销毁临时(通常隐式地,让它超出范围).如果你这样做,指针将进入临时指针,并在它被销毁时失效.
如果你使用shrink_to_fit它(可能)不会使迭代器/指针无效,但可能没有任何影响(标准指定它是一个非绑定请求,并没有说它使迭代器/指针无效).
M.M*_*M.M 10
如果在不调整大小的情况下对矢量进行混洗,则指针仍然指向相同的位置,该位置可能包含不同的元素.
如果向量被调整为更大,则指针被称为"无效"并且它具有与未初始化指针相同的状态,即评估它或尝试读取它会导致未定义的行为.
Mat*_*lia 10
如果我现在对矢量进行混洗,它是否仍然指向相同的元素(第三个),还是指向使用到第三个元素移动的新位置?
改组元素只是通过数组中的各种"桶"复制/交换元素,而指针只指向"内存中的固定位置".因此,它将继续指向阵列中第三个位置的任何位置.
然后我想让问题更加通用:当向量展开,缩小或洗牌时,向量中元素的指针和迭代器如何表现?
展开:所有迭代器/引用/指针都可能无效.
减少:只要他们在删除之前指向元素,它们将保持有效,除非你做了shrink_to_fit.您删除的元素的迭代器/指针显然无效.
改组:你正在移动东西而不会导致重新分配,因此迭代器和引用仍然有效.
请注意,所有这些内容通常都会在大多数C++文档源中报告.
要记住向量的概念规则是它们只是一个围绕动态数组的框,并且迭代器和指向元素的指针在概念上是相同的(实际上,std::vector<T>::iterator可能是typedeffor T *).对于引用(伪装的指针)也是如此.
如果操作可能需要重新分配数组(=数组需要增长,或者您明确要求它缩小),那么所有迭代器/指针/引用都将失效.如果删除元素,则指向过矢量"概念结束"的指针将指向无效元素.如果大小保持不变,则不需要重新分配.
地址不会改变,但存储在该地址的值将会改变.
#include <iostream>
#include <algorithm>
static void print_vec(const std::vector<int>& v) {
for (int i = 0; i < v.size(); ++i) {
std::cout << "Value: " << v.at(i) << " Address: " << &v.at(i) << std::endl;
}
}
static void shuffle_vec(std::vector<int>& v) {
auto engine = std::default_random_engine{};
std::shuffle(v.begin(), v.end(), engine);
}
int main() {
std::vector<int> v{1, 2, 3, 4, 5};
std::cout << "Before Shuffle: " << std::endl;
print_vec(v);
shuffle_vec(v);
std::cout << "After Shuffle: " << std::endl;
print_vec(v);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出:
Before Shuffle:
Value: 1 Address: 0x16eb320
Value: 2 Address: 0x16eb324
Value: 3 Address: 0x16eb328
Value: 4 Address: 0x16eb32c
Value: 5 Address: 0x16eb330
After Shuffle:
Value: 3 Address: 0x16eb320
Value: 1 Address: 0x16eb324
Value: 5 Address: 0x16eb328
Value: 4 Address: 0x16eb32c
Value: 2 Address: 0x16eb330
Run Code Online (Sandbox Code Playgroud)
实际上,向量是代码维护的连续数据缓冲区.每个元素以类似数组的方式设置为与下一个元素相邻.
当元素四处移动时,实际上它们只是四处移动.指针指向该缓冲区中的位置,因此如果元素移动,实际上指针最终指向其他位置.
但是,C++标准更严格.当迭代器失效时,引用和指向该位置的指针也是如此.有许多操作可以使迭代器无效,这在逻辑上不会改变数组实际上将成为同一缓冲区的事实.例如,如果您.erase是一个元素,它会使该位置和之后的每个迭代器无效.
在实践中,指向元素的指针最终将指向列表中的"下一个"元素,但标准并不能保证这一点.
std::shuffle不会使任何迭代器无效.它只是改变那里存储的值.所以指向第n个元素的指针在实践中都是如此,理论上仍然指向第n个元素.
展开向量时,如果将其展开,则.capacity()所有迭代器都将失效.在实践中,它实际上将数据移动到一个新位置,指针现在正在敲击指针.
当您减少(通过.erase(it)或.erase(a,b))时,第一个参数处或之后的所有迭代器都将失效.这意味着对这些元素的引用和指针也会失效.在实践中,他们现在将引用"进一步向下"的元素(如果存在这样的元素),因为两者都.erase不会导致缓冲区重新分配,但标准不保证这一点.
还有其他操作可以使迭代器无效. .shrink_to_fit()可以,vector<X>(vec).swap(vec)(缩小到适合的C++ 03版本),以及.reserve()超出规模的操作.capacity().
.capcity()在实践中和理论上,导致更改的操作实际上会使指针无效(或使指针指向超出端的指针).
阅读您调用的每个功能的文档.如果您不知道何时以及如何调用它以及它的作用,那么您为什么要使用它?
通常,您不能依赖地址或数组等实现概念,也不能依赖测试程序.当迭代器对于特定容器,迭代器和运算符的元素无效或无效时,必须读取.
vector::shrink_to_fit使
vector::resize相同或更小的所有迭代器无效,使新大小之外的迭代器完全
vector::resize无效,使得所有迭代器无效
从C++ 14标准[iterator.requirements.general]:
[P] ointers是迭代器.取消引用已失效的迭代器的效果未定义.
http://en.cppreference.com/w/cpp/container/vector
std::vector是一个封装动态大小数组的序列容器.
元素是连续存储的,这意味着元素不仅可以通过迭代器访问,还可以使用常规指向元素的偏移量来访问.迭代器RandomAccessIterator
迭代器失效
swap, std::swap从不
shrink_to_fit总是
resize如果向量改变了容量,所有这些都是.如果不是,只有插入点后的那些.
http://en.cppreference.com/w/cpp/container/vector/resize
当调整大小到较小时,向量容量永远不会减少,因为这会使所有迭代器无效,而不是仅通过等效
pop_back()调用序列无效的那些迭代器.
经过vector::shuffle迭代器/指针是不变,但取消引用新值.
因为使迭代器不变的shuffle用法swap:
http://en.cppreference.com/w/cpp/algorithm/random_shuffle
Run Code Online (Sandbox Code Playgroud)template< class RandomIt, class URNG > void shuffle( RandomIt first, RandomIt last, URNG&& g );RandomIt必须满足ValueSwappable和RandomAccessIterator的要求.
http://en.cppreference.com/w/cpp/concept/Iterator
Iterator是其他迭代器类型使用的基本概念:InputIterator,OutputIterator,ForwardIterator,BidirectionalIterator和RandomAccessIterator.迭代器可以被认为是指针的抽象.[...]
` - lvalues类型它满足Swappable [...]
http://en.cppreference.com/w/cpp/concept/ValueSwappable
如果
1)类型T满足迭代器要求,则类型T是ValueSwappable
2)对于任何类型为T的可解除引用的对象x(即除了结束迭代器之外的任何值),*x满足可交换的要求.
http://en.cppreference.com/w/cpp/concept/Swappable
Run Code Online (Sandbox Code Playgroud)using std::swap; swap(u, t);在调用之后,t的值是在调用之前由u保持的值,并且u的值是在调用之前由t保持的值.
| 归档时间: |
|
| 查看次数: |
3056 次 |
| 最近记录: |