向量如何分配内存

时间:2010-07-03 06:57:57

标签: c++

斐伊川   我知道当需要push_back某些项时,向量分配了连续的固定内存。如果它不能适应它,它将分配新内存并将旧值复制到其中并删除旧内存。 如果是以下代码的工作原理

#include<iostream>  
#include<vector>  
using namespace std;   

class Test   
{
public :   
    int val;   
    Test()   
    {
        val=0;   
    }   
};   


int main()   
{
    vector<Test>vec;   
    Test t[10];   
    for (int i=0;i<5;i++)   
        vec.push_back(t[i]);   
    cout<<vec.capacity()<<endl; //printing 8   
    Test* obj=&vec[2];   
    obj->val=2;   
    cout<<obj<<endl;   
    for (int i=0;i<5;i++) //Adding 5 elements more 
        vec.push_back(t[i]);   
    Test* obk=&vec[2];    
    cout<<obk->val<<endl;    
    cout<<obj->val<<endl;    
    cout<<obj<<endl;  
    cout<<obk<<endl;  
}  

这里,如果你看到obj正在接收vec [2]的指针,我的机器中的值即将到来0x8bcb048。然后我又插入了5个项目,因此vector将分配新的内存。现在如果我从向量中获取obk [2]它即将到来的地址为0x8bcb070。但是,如果我试图在obj的帮助下接受我没有给出任何问题。任何原因?

4 个答案:

答案 0 :(得分:6)

  

但是,如果我试图在obj的帮助下访问它,它没有给出任何问题。有什么原因吗?

这是未定义的行为 - 它似乎起作用的事实仅仅是因为运气(无论运气好坏都是意见问题)。

基本上你是解除引用'悬空'指针。就像你取消引用一个已经被释放的内存块的指针一样,你只需读出看起来像是具有合理值的旧陈旧数据。或者你可能会读出看似垃圾的东西。或者你可能会导致段错误。

有一件事是肯定的 - 这是一个错误,无论它是否像一个人一样。

答案 1 :(得分:4)

当向量重新分配时,在重新分配之前获得的所有迭代器,指针和引用都将失效。使用它们会导致未定义的行为,其中包括“显然没有任何问题”。

要使问题可视化,您可以在构造函数和析构函数中插入调试输出。您还可以记录任何时间点存在的对象:

class Test;

std::set<Test*> valid_Test_objects;

class Test
{
    int val;

public:

    Test() : val(0)
    {
        valid_Test_objects.insert(this);
        std::cout << "constructed Test object @ " << this << std::endl;
    }

    Test(const Test& that) : val(that.val)
    {
        std::cout << "constructed Test object @ " << this << std::endl;
        valid_Test_objects.insert(this);
    }

    ~Test()
    {
        std::cout << "destructing Test object @ " << this << std::endl;
        valid_Test_objects.erase(this);
    }

    int value()
    {
        std::cout << "  accessing Test object @ " << this << std::endl;
        if (valid_Test_objects.find(this) == valid_Test_objects.end())
        {
            abort();
        }
        return val;
    }
};

int main()
{
    std::vector<Test> vec;
    vec.reserve(3);

    Test x;
    vec.push_back(x);
    Test* p = &vec[0];
    std::cout << p->value() << std::endl;

    std::vector<Test>::size_type cap = vec.capacity();
    while (cap == vec.capacity()) vec.push_back(x);

    std::cout << p->value() << std::endl;
}

很遗憾,当p->value()无效时,我们甚至不应该尝试拨打p。享受您在未定义的行为土地上的逗留; - )

答案 2 :(得分:4)

向量是动态数组。你是正确的当它们溢出时它们被重新分配到其他地方并且所有早期初始化的指针/迭代器(通常用于向量也被实现为指针,尽管标准不需要它)/地址引用变得无效。最后释放的内存空间最终被释放。

以下是事件以简单化术语发生的方式:

  1. 目前可用空间不足。

  2. 获取新的内存空间(k次(一般为k = 2)与原始内存大小一样大)

  3. 将当前数组复制到新的内存位置

  4. old = current; current = new; {这确保了单次插入的原子性}

  5. 释放旧记忆。

  6. 请注意,旧内存位置的数据不会被破坏或重置。因此,当需要再次使用可能会或可能不会重用的资源时。但是你拥有的原始内存位置是一个错误的位置,必须始终避免。

答案 3 :(得分:1)

如果您在尝试访问“obj”时询问为什么没有崩溃,那么我会说您应该尝试在“发布”模式下运行它并查看。在任何情况下,都不应该访问obj,因为当向量增加其容量时,&amp; vec [2]返回的指针无效。它仍然可能指向恰好分配给您的进程的一些随机垃圾。