我正在从C转向C ++,正在玩矢量。
这是我尝试的一些代码:
#include <iostream>
#include <vector>
using namespace std ;
#define VSIZE 10
class vClass ;
vector <vClass> myVect(VSIZE) ;
class vClass
{
int pos1 ;
public:
void getInfo()
{
pos1 = this - myVect.data() ;
cout << pos1 << endl ;
}
};
//===============================
vClass vArray[VSIZE] ;
int main()
{
cout << endl << "Size of vClass: " << sizeof(vClass) << endl << endl ;
cout << "Size of myVect: " << sizeof(myVect) << endl << endl ;
cout << "Size of myVect[0]: " << sizeof myVect[0] << endl << endl ;
cout << endl << "Locations:" << endl ;
for(int i= 0; i < VSIZE; i++) myVect[i].getInfo();
return 0 ;
}
我得到以下输出:
Size of vClass: 8
Size of myVect: 12
Size of myVect[0]: 8
Locations:
0
1
2
3
4
5
6
7
8
9
我对以下内容感到好奇:
vClass的大小为8个字节。但是,vClass类型的10元素向量显示12字节的大小。为什么是这样 ?我期待8x10 = 80字节。
表达式:this - myVect.data()
导致输出元素的索引。
我希望我需要(this - myVect,data())/sizeof(vClass)
。
矢量总是这样吗?
我尝试使用数组:vClass myArray[10]
和(this - myArray)
但在这里我得到了一个连续的十六进制数字列表(地址?)。
所以'this'指针以某种方式链接到向量,而不是数组?
如果有人能解释或证实这种行为,我会很感激。
我正在使用g ++ 4.9.2,使用c ++ 14标准在树莓派上编译它。
谢谢
答案 0 :(得分:2)
矢量对象本身始终具有固定大小。它包含诸如元素数量和指向某些堆存储的指针之类的信息。向量的元素存储在堆上,因此元素的数量可以增长(或缩小)。
减去两个指针可以得到指针之间的元素数量。这不是矢量特有的。您似乎将此与计算数组大小(sizeof(vArray)/sizeof(vClass)
)的方法混淆。向量不需要这样,因为它有size()
成员。
this
指针仅出现在类的成员函数中。它告诉您函数调用的可能很多类对象的哪个实例。当您执行myVect[i].getInfo()
时,this
会在myVect[i]
函数内保留getInfo
的地址。
答案 1 :(得分:2)
sizeof(myVect)
告诉你矢量对象本身的大小(以字节为单位很可能是3个指针)。它没有说明矢量中存储的元素数量;这些由向量管理,但存储在动态分配的内存中,因此它们不会出现sizeof(myVect)
。
您所访问的信息可能是myVect.size()
,它为您提供了向量中 number 的元素,或myVect.size() * sizeof(vClass)
,它们将给出占用的字节数那些向量元素。请注意,后者实际上没有说明向量使用的内存,它可以过度分配以保留用于添加元素的空间等。
this - myVect.data()
很可能是未定义的行为,因为您无法保证使用指向同一阵列的指针。但是如果定义得很好,它就会像任何其他指针算法一样工作(与C中相同):a - b
其中a
和b
属于T*
类型给出了T
和a
之间的b
个对象的数量,而不是它们的字节距离。
作为旁注:std:vector
要求其模板参数为完整类型 - 使用已声明但尚未定义的类来实例化它是错误的,因为您正在执行此操作。它可能恰好(似乎)有效,但那是纯粹的机会。
答案 2 :(得分:2)
令人惊讶的是,这是在Visual Studio 2015中编译的。
- vClass的大小为8个字节。但是,vClass类型的10元素向量显示12字节的大小。为什么是这样 ?我期待8x10 = 80字节。
醇>
嗯,vector
只是一个句柄。它的元素存储在堆中。所有vector
需求都是指向堆中这些元素的指针(data
),当前元素数(size
)和最大元素数(capacity
) 。
因此,如果增长/缩小向量,则句柄的大小始终保持不变,只有堆中的数组才会发生变化。
vector< vClass > myVect;
// Stack - vector
[ vector: data, size, capacity ]
|
|
V
// Heap - array managed by vector
[ vClass0 ][ vClass1 ]...
// Each has completely unrelated addresses
- 表达式:this - myVect.data()导致输出元素的索引。我希望我需要(这个 - myVect,数据())/的sizeof(vClass)。向量总是如此吗? 我尝试了一个数组:vClass myArray [10]和(这 - myArray)但是这里我得到了一个连续的十六进制数列表 (地址?)。所以'this'指针以某种方式链接到矢量, 但不是阵列?
醇>
这是有效的,因为this
和myVect.data()
都是托管数组中vClass
的指针。您不需要除以sizeof(vClass)
,因为指针算术考虑了它们指向的类型的大小。
sizeof(vClass) == sizeof(int)
,当你递增,递减或减去指针时,它们会在与指向类型相同的块中移动,因此你不必显式增加具有正确大小的指针。你确实得到了索引0,1,2,......但换句话说,这也意味着 2 vClass'es适合这个地址和这个地址。
当您使用向量数组尝试此操作时,每个向量在内存中是连续的(每个句柄)。而且,每个向量指向堆中自己的数组,因此每个数组都是完全不相关的。但我不知道你测试的代码到底是什么,所以我不会对此发表评论。
this
指针,假设您的vClass
个实例属于vector
,实际上是vector
的内部数组,而不是{{1}处理自己。
这是有效的,因为您的类是POD类。如果要创建一个指针向量(每个实例都在不相关的地址中),或者使用指向基类的指针(不相关地址中的每个实例和派生类型都有不同的大小),那么这将不起作用。
虽然这个例子有效,但我不鼓励你这样做(除此之外只有你的向量是全局变量才有效)。你正在从C转向C ++,我理解旧习惯很难,但除非你真的必须使用它,否则应避免使用指针算法。
你可以通过调用vector
方法得到vector
的大小(你做对了),如果你需要知道一个元素的索引,你就会知道迭代向量的时间。 (还有其他方法可以肯定,但这取决于你)
编辑:关于索引和迭代
迭代数组或向量时,可以按索引进行迭代(以及其他迭代形式)。很明显,每次迭代你都知道一个索引,
size()
这基本上就是你在打印矢量时所做的。
如果您需要知道特定索引而不进行迭代(无论是否需要它来擦除元素,或直接访问等),您可以,例如,拥有一个具有相关索引的单独容器,或将其存储在对象中作为ID,如,
for ( int i = 0; i < myVect.size(); ++i ) {
myVector[ i ]; // <-- here's an object with index i, easy
}
然后,当您将元素推入向量时,您可以设置其ID,并且他们将知道其索引。当然,如果对矢量进行排序,则必须自己更新索引。它们不会像你使用指针那样“自动更新”,但你的实例必须确切地知道它们所在的容器,并且必须使用实现细节来找到它们的索引(特别是对于向量),并且包含的对象不应该需要这样做。
正如我所说,有很多解决方案。这取决于你想做什么。
答案 3 :(得分:1)
我没有得到这个输出,我根据juanchopanza的评论得到编译器错误。
vector
对象由(实现定义的)元数据组成,包括指针到它包含的数据(您从data()
获得的数据。)会发现矢量的大小是恒定的,而不会随着size()
而改变。
您的this
指针属于vClass *
类型。指针p
上的指针算术始终与sizeof( p )
的倍数一起使用。
话虽这么说,你真的不应该像这样捅一个班级的内部人员。 ; - )