关于c ++中向量的观察

时间:2015-10-07 08:30:57

标签: c++ vector raspberry-pi

我正在从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

我对以下内容感到好奇:

  1. vClass的大小为8个字节。但是,vClass类型的10元素向量显示12字节的大小。为什么是这样 ?我期待8x10 = 80字节。

  2. 表达式:this - myVect.data()导致输出元素的索引。 我希望我需要(this - myVect,data())/sizeof(vClass)。 矢量总是这样吗?
    我尝试使用数组:vClass myArray[10](this - myArray) 但在这里我得到了一个连续的十六进制数字列表(地址?)。 所以'this'指针以某种方式链接到向量,而不是数组?

  3. 如果有人能解释或证实这种行为,我会很感激。

    我正在使用g ++ 4.9.2,使用c ++ 14标准在树莓派上编译它。

    谢谢

4 个答案:

答案 0 :(得分:2)

  1. 矢量对象本身始终具有固定大小。它包含诸如元素数量和指向某些堆存储的指针之类的信息。向量的元素存储在堆上,因此元素的数量可以增长(或缩小)。

  2. 减去两个指针可以得到指针之间的元素数量。这不是矢量特有的。您似乎将此与计算数组大小(sizeof(vArray)/sizeof(vClass))的方法混淆。向量不需要这样,因为它有size()成员。

  3. 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其中ab属于T*类型给出了Ta之间的b个对象的数量,而不是它们的字节距离。

作为旁注:std:vector要求其模板参数为完整类型 - 使用已声明但尚未定义的类来实例化它是错误的,因为您正在执行此操作。它可能恰好(似乎)有效,但那是纯粹的机会。

答案 2 :(得分:2)

令人惊讶的是,这是在Visual Studio 2015中编译的。

  
      
  1. vClass的大小为8个字节。但是,vClass类型的10元素向量显示12字节的大小。为什么是这样 ?我期待8x10 = 80字节。
  2.   

嗯,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
  
      
  1. 表达式:this - myVect.data()导致输出元素的索引。我希望我需要(这个 -   myVect,数据())/的sizeof(vClass)。向量总是如此吗?   我尝试了一个数组:vClass myArray [10]和(这 -   myArray)但是这里我得到了一个连续的十六进制数列表   (地址?)。所以'this'指针以某种方式链接到矢量,   但不是阵列?
  2.   

这是有效的,因为thismyVect.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的评论得到编译器错误。

  1. vector对象由(实现定义的)元数据组成,包括指针到它包含的数据(您从data()获得的数据。)会发现矢量的大小是恒定的,而不会随着size()而改变。

  2. 您的this指针属于vClass *类型。指针p上的指针算术始终与sizeof( p )的倍数一起使用。

  3. 话虽这么说,你真的不应该像这样捅一个班级的内部人员。 ; - )

相关问题