按值传递的C ++向量:我做对了吗?

时间:2015-11-06 13:25:41

标签: c++ vector heap-memory

我们说我有这样的结构:

struct typeA
{
    long first;
    string second
    double third;
};

如果我宣布

typeA myArray[100];

然后myArray存储在堆栈中,消耗sizeof(typeA)* 100字节的垃圾数据(直到我存储一些实际数据,至少)。

每当我将此数组作为参数传递时,我总是会将指针传递给堆栈中第一个元素。所以指针从堆栈到堆栈。

但如果我宣布

vector<int> myVector (4, 100);

然后myVector对象实际存储在堆栈中,它包含一个指向存储在堆中的4 * sizeof(int)字节数组的第一个元素的指针,其中存储了实际数据。所以指针从堆栈变为堆。

每当我将此向量作为参数传递时,如果我将它添加到参数列表中,如下所示:

vector<int> parameterVector

该函数获取myVector对象的副本并将其存储在堆栈中。

但如果我这样做:

vector<int> &parameterVector

该函数获取存储在堆栈中的对myVector的引用,所以我现在有一个存储在堆栈中的变量,引用一个也存储在堆栈中的myVector对象,其中包含一个指向数组的指针存储在堆中的实际元素。

这是对的吗?

我有点怀疑:

  1. 实际的元素是否存储在堆中的静态数组(从C继承,用方括号表示)中?
  2. myVector对象是否只有一个指向第一个元素的指针,或者它有多个指向每个元素的指针?
  3. 因此,按值传递矢量并不会造成很大的问题,因为复制的唯一内容是矢量对象,而不是实际的元素。是这样吗?
  4. 如果我把整个事情搞错了,并且在按值传递矢量参数时也会复制实际元素,那么为什么C ++会允许这样做,考虑到它会阻止静态数组呢? (据我所知,静态数组总是作为第一个元素的引用传递。)
  5. 谢谢!

2 个答案:

答案 0 :(得分:2)

  

实际的元素是否存储在堆中的静态数组(从C继承,用方括号表示)中?

通常,矢量的元素使用动态数组(如

)存储在空闲存储中
some_type* some_name = new some_type[some_size]
  

myVector对象是否只有一个指向第一个元素的指针,或者它有多个指向每个元素的指针?

通常,向量将具有指向第一个元素,大小变量和容量的指针。它可能有更多,但这些是实现细节,并没有由标准定义。

  

因此,按值传递矢量并不会造成太大问题,因为复制的唯一内容是矢量对象,而不是实际的元素。是这样吗?

没有。复制向量是O(N)操作,因为它必须复制向量的每个元素。如果没有那么你将有两个使用相同底层数组的向量,如果一个被销毁,那么它将从另一个下面删除数组。

答案 1 :(得分:1)

  
      
  1. 实际的元素是否存储在堆中的静态数组(从C继承,用方括号表示)中?
  2.   

std::vector<>将在堆上为您使用标准分配器的所有元素分配内存。它将管理该内存并在必要时重新分配。所以不,没有静态数组。它更像你在C中处理动态数组,但没有所有的陷阱。

如果您正在寻找C-Arrays的现代替代品,请查看std::array<>。请注意,std::array<>也会复制所有元素。如果这就是你的意思,请参考。

  
      
  1. myVector对象是否只有一个指向第一个元素的指针,或者它有多个指向每个元素的指针?
  2.   

std::vector通常是指向第一个元素的指针,一个大小和一些内部使用的位。但细节实际上是特定于实现的。

  
      
  1. 因此,按值传递矢量并不会造成很大的问题,因为复制的唯一内容是矢量对象,而不是实际的元素。是这样吗?
  2.   

没有。每当矢量对象被复制到另一个矢量对象时,所有元素都将被复制。

  
      
  1. 如果我把整个事情搞错了,并且在按值传递矢量参数时也会复制实际元素,那么为什么C ++会允许这样做,考虑到它会阻止静态数组呢? (据我所知,静态数组总是作为第一个元素的引用传递。)
  2.   

&#34;静态数组&#34;是C-Legacy。您不应该在新代码中再使用它们。如果您想通过引用传递矢量,请执行此操作,不会复制任何内容。如果您想要移动矢量,请移动它,而不是复制它。每当你告诉编译器时,你想复制一个对象,它就会。

好的,为什么会这样?

C行为在某种程度上与语言的其他部分不一致。当你传递一个int时,它会被复制,当你传递一个struct时,它会被复制,当你传递一个指针时,它会被复制,但是当你传递一个数组时,数组不会被复制,而是一个指针到它的第一个元素。

所以C ++的方式更加一致。通过值复制一切,通过引用传递不是。使用C ++ 11移动构造函数,可以通过移动对象来传递对象。这意味着,原始向量将保留为空,而新的向量将接管原始内存块的负责。