Con*_*nst 46 c++ stdvector language-lawyer c++11 stdarray
任何人都可以解释一下记忆的布局
std::vector<std::array<int, 5>> vec(2)
Run Code Online (Sandbox Code Playgroud)
它是否提供具有2行5个元素的2D数组的连续内存块?
据我所知,矢量矢量
std::vector<std::vector<int>> vec(2, std::vector<int>(5))
Run Code Online (Sandbox Code Playgroud)
提供存储器中不同位置的两个 长度为 5个元素的连续数组的存储器布局.
对于数组的向量是否相同?
Lig*_*ica 58
数组没有任何间接,但只是"直接"存储它们的数据.也就是说,std::array<int, 5>字面上int连续五个s,平坦.并且,与向量一样,它们不会在元素之间添加填充,因此它们"内部连续".
然而,该std::array物体本身可能会超过设定的元素更大!允许有像填充这样的尾随"东西".所以,尽管有可能,但不一定是正确的,你的数据将全部是在第一种情况下连续的.
An int
+----+
| |
+----+
A vector of 2 x int
+----+----+----+-----+ +----+----+
| housekeeping | ptr | | 1 | 2 |
+----+----+----+-----+ +----+----+
| ^
\-----------
An std::array<int, 5>
+----+----+----+----+----+----------->
| 1 | 2 | 3 | 4 | 5 | possible cruft/padding....
+----+----+----+----+----+----------->
A vector of 2 x std::array<int, 5>
+----+----+----+-----+ +----+----+----+----+----+----------------------------+----+----+----+----+----+----------->
| housekeeping | ptr | | 1 | 2 | 3 | 4 | 5 | possible cruft/padding.... | 1 | 2 | 3 | 4 | 5 | possible cruft/padding....
+----+----+----+-----+ +----+----+----+----+----+----------------------------+----+----+----+----+----+----------->
| ^
\-----------
Run Code Online (Sandbox Code Playgroud)
而且,即使它是由于别名规则,你是否能够使用单个int*导航所有10个数字可能是另一回事!
总而言之,10 int秒的向量将更清晰,更完整,并且可能更安全.
在向量向量的情况下,向量实际上只是一个指针加上一些内务处理,因此间接(如你所说).
Som*_*ude 18
std::vector和之间的最大区别std::array是它std::vector包含指向它包装的内存的指针,同时std::array包含实际的数组本身.
这意味着矢量矢量就像一个锯齿状阵列.
对于数组矢量,std::array对象将连续放置,但与矢量对象分开.请注意,std::array对象本身可能比它们包含的数组大,如果是,那么数据将不是连续的.
最后一位也意味着数组(普通C风格或者std::array)std::array也可能不会连续保持数据.std::array数组中的对象将是连续的,但不是数据.
保证"多维"数组的连续数据的唯一方法是嵌套的普通C风格数组.
Bat*_*eba 11
C++标准不保证std::array在数组末尾不包含任何有效负载,因此你不能假设后续数组的第一个元素就在前一个数组的最后一个元素之后.
即使是这种情况,尝试通过指针算法在指向不同数组中的元素的指针上到达数组中的任何元素的行为也是未定义的.这是因为指针算法仅在数组中有效.
以上也适用于std::array<std::array>.
static_assert(sizeof(std::array<int,5>)==5*sizeof(int));
Run Code Online (Sandbox Code Playgroud)
以上缓解了在一个结尾处有任何填充std::array.没有主要的编译器会导致上述内容未能达到此日期,我打赌将来也不会.
当且仅当上述情况失败时,s std::vector<std::array<int,5>> v(2)之间才会有"差距" std::array.
这没有你想要的那么多; 生成的指针如下:
int* ptr = &v[0][0];
Run Code Online (Sandbox Code Playgroud)
只有一个有效域ptr+5,并且解除引用ptr+5是未定义的行为.
这是由于别名规则造成的; 即使您知道它在那里,也不允许"走"过一个对象的末尾,即使您知道它在那里,除非您首先往返某些类型(例如char*)允许较少限制的指针算法.
反过来,该规则允许编译器通过哪个指针来推断正在访问哪些数据,而不必证明任意指针算法可以让您到达外部对象.
所以:
struct bob {
int x,y,z;
};
bob b {1,2,3};
int* py = &b.y;
Run Code Online (Sandbox Code Playgroud)
不管你做什么py作为int*,你不能合法修改x或z用它.
*py = 77;
py[-1]=3;
std::cout << b.x;
Run Code Online (Sandbox Code Playgroud)
编译器可以优化std::cout线条以简单地打印1,因为py[-1]=3可能会尝试修改b.x,但通过这种方式这样做是未定义的行为.
同样的限制会阻止您从第一个阵列进入std::vector第二个阵列(即超越ptr+4).
创建ptr+5是合法的,但仅作为一个过去的指针.ptr+5 == &v[1][0]即使在每个主要硬件系统上的每个编译器中它们的二进制值绝对相同,也不会在结果中指定比较.
如果你想进一步深入兔子洞,std::vector<int>由于指针别名的这些限制,甚至不可能在C++本身内实现.最后我检查了(这是在c ++ 17之前,但我没有在C++ 17中看到解决方案)标准委员会正在努力解决这个问题,但我不知道任何此类努力的状态.(这比您想象的要少,因为没有什么要求std::vector<int>在符合标准的C++中实现;它必须只具有标准定义的行为.它可以在内部使用特定于编译器的扩展.)
| 归档时间: |
|
| 查看次数: |
3262 次 |
| 最近记录: |