c ++矢量对象地址和数据地址混淆

时间:2018-02-15 20:34:32

标签: c++ pointers memory memory-management reference

我创建了一个向量 a 并尝试显示& a & a [0] 。地址非常不同。对象地址通常与第一个元素地址相同吗?对象记忆是不是连续的?我注意到& a + 1 & a 之间的地址差异与整个矢量元素的大小完全相同,在这种情况下为12个字节。它看起来像是我整个矢量的副本。

#include <iostream>
#include <vector>

using namespace std;

int main(){

    vector<int> a ={3,5,8};
    cout<<"vector object address: "<<&a<<endl;
    cout<<"vector object address +1: "<<&a+1<<endl;
    cout<<"vector data[0] address: "<<&a[0]<<endl;
    cout<<"vector data[1] address: "<<&a[1]<<endl;


    return 0;

}

任何人都可以向我解释矢量对象的工作原理吗?下面是代码输出:

vector object address: 0034FEBC
vector object address +1: 0034FEC8
vector data[0] address: 007D8208
vector data[1] address: 007D820C

4 个答案:

答案 0 :(得分:0)

矢量的工作原理是实现定义的。但是,默认情况下,它们需要在免费存储上动态存储其元素。这意味着当您创建std::vector时,它会分别为其成员获取内存。

它可以实现如下:

template<typename T>
class vector
{
public:

    // The returned element will not have the same address as this
    T& operator[](std::size_t n) { return m_begin[n]; } 

private:
    T* m_begin; // start of internal array
    T* m_top;   // end of contained elements
    T* m_end;   // end of internal array
};

注意:上述模型中缺少重要部分

元素的地址直接存储在矢量对象中,而不是元素本身。

答案 1 :(得分:0)

您所看到的内容的解释是std::vector不像原始c风格数组那样遵循array decaying的相同规则:

#include <iostream>
using std::cout;
using std::endl;

int main() {

    int a[] ={3,5,8};
    cout<<"raw array object address: "<<&a<<endl;
    cout<<"raw array object address +1: "<<&a+1<<endl; // adds sizeof(a)
    cout<<"raw array data[0] address: "<<&a[0]<<endl;  // same as a + 0
    cout<<"raw array data[1] address: "<<&a[1]<<endl;  // same as a + sizeof(int)
}

输出:

raw array object address: 0x7ffd02ca2eb4
raw array object address +1: 0x7ffd02ca2ec0
raw array data[0] address: 0x7ffd02ca2eb4
raw array data[1] address: 0x7ffd02ca2eb8

See live demo

  

有人可以向我解释矢量对象的工作原理吗?

std::vector实例是非POD变量,并且在本地存储中具有自己的地址。它只包装实际用于存储数据的底层内存地址。 实现定义究竟是什么,但您可以认为至少有一个实习指针,并且allocator concept用于获取内存。 跟踪当前大小,并复制到重新分配的内存也是如此。

std::vector::data()函数专用于访问有保证的连续内存块。

您应该注意到,通过上述data()函数获得的指针不稳定,并且在某种程度上操作std::vector后可能会失效。

另外值得一提的是std::array在其他标准容器中例外:

#include <iostream>
#include <array>

using std::array;
using std::cout;
using std::endl;

int main() {

    array<int,3> a ={3,5,8};
    cout<<"std::array object address: "<<&a<<endl; // Note these addresses ...
    cout<<"std::array object address +1: "<<&a+1<<endl;
    cout<<"std::array data[0] address: "<<&a[0]<<endl; // are the same
    cout<<"std::array data[1] address: "<<&a[1]<<endl;
}

输出:

std::array object address: 0x7ffe72f1cf24
std::array object address +1: 0x7ffe72f1cf30
std::array data[0] address: 0x7ffe72f1cf24
std::array data[1] address: 0x7ffe72f1cf28

Live demo

答案 2 :(得分:0)

除了@Galik所说的,我还会提到&a&a+1之间的关系并不是你所期望的。考虑:

#include<iostream>
#include<vector>

int main() {
    std::vector<int> a = {3,5,8,234,324,324};
    std::vector<int> b = {1};
    std::cout<<sizeof(a)<<std::endl;
    std::cout<<&a<<std::endl;
    std::cout<<&a+1<<std::endl;
    std::cout<<sizeof(b)<<std::endl;
    std::cout<<&b<<std::endl;
    std::cout<<&b+1<<std::endl;
    return 0;
}

我的输出是:

24
0x7fffc48c6ca0
0x7fffc48c6cb8
24
0x7fffc48c6cc0
0x7fffc48c6cd8

两个数组都有sizeof 24,并且向指针添加1会使地址增加相同的数量(18十六进制为24)。无论元素数量多少!你正在做的是查看向量的数据结构的大小,它包含一个指向数组的指针,因此没有得到“真正的”大小(它是真实的,只是该类包含一个指针,而不是数据,因此不受其影响。)

这与数据本身无关,保证连续,如您的示例所示([0][1]的两个地址完全由sizeof(int)==4分隔你的情况)。

答案 3 :(得分:0)

向量由两部分组成。一个是对象本身,它是固定大小。另一个是向量中包含的数据,它是可变的。向量对象的一个​​成员将是向量包含的数据的指针&a返回一个指向矢量对象的指针,&a[0]返回一个指针,该指针指向与该对象位于同一位置的的数据。

&a为您提供指向矢量对象的指针。当您执行&a+1时,您将使用指针算法,这将为您提供指向向量数组中下一个向量的指针。由于你没有数组,&a+1正在返回一个无效指针,但是C ++没有任何方法可以知道它。