这两个班级有什么区别?

时间:2009-03-25 16:47:23

标签: c++ memory

下面,我my_ints声明为指针。我不知道将分配内存的位置。请教我这里!

#include <iostream>
#include <vector>

class FieldStorage
{
private:
    std::vector<int> my_ints;

public:
    FieldStorage()
    {
        my_ints.push_back(1);
        my_ints.push_back(2);
    }

    void displayAll()
    {
        for (int i = 0; i < my_ints.size(); i++)
        {
            std::cout << my_ints[i] << std::endl;
        }
    }
};

在这里,我将字段my_ints声明为指针:

#include <iostream>
#include <vector>

class FieldStorage
{
private:
    std::vector<int> *my_ints;

public:
    FieldStorage()
    {
        my_ints = new std::vector<int>();
        my_ints->push_back(1);
        my_ints->push_back(2);
    }

    void displayAll()
    {
        for (int i = 0; i < my_ints->size(); i++)
        {
            std::cout << (*my_ints)[i] << std::endl;
        }
    }

    ~FieldStorage()
    {
        delete my_ints;
    }
};

main()功能测试:

int main()
{
    FieldStorage obj;
    obj.displayAll();
    return 0;
}

它们都产生相同的结果。有什么区别?

11 个答案:

答案 0 :(得分:13)

在内存管理方面,这两个类几乎完全相同。其他几个响应者已经建议两者之间存在差异,因为一个是在堆栈上分配存储而另一个在堆上,但这不一定是真的,即使在它是真的情况下,它也是非常误导的。实际上,所有不同的是分配了vector元数据;无论如何,vector中的实际底层存储都是从堆中分配的。

看到这一点有点棘手,因为您使用的是std::vector,因此隐藏了具体的实现细节。但基本上,std::vector的实现方式如下:

template <class T>
class vector {
public:
    vector() : mCapacity(0), mSize(0), mData(0) { }
    ~vector() { if (mData) delete[] mData; }
    ...
protected:
    int mCapacity;
    int mSize;
    T *mData;
};

正如您所看到的,vector类本身只有几个成员 - 容量,大小和指向动态分配的内存块的指针,该内存块将存储向量的实际内容。

在您的示例中,唯一的区别是这些少数字段的存储来自何处。在第一个示例中,存储是从您用于包含类的任何存储中分配的 - 如果它是堆分配的,那么vector的那些位也是如此。如果您的容器是堆栈分配的,那么vector的那些位也是如此。

在第二个示例中,vector的那些位始终是堆分配的。

在这两个示例中,vector的实际 meat - 它的内容 - 是从堆中分配的,您无法更改它。

其他人已经指出你的第二个例子中有内存泄漏,这也是事实。确保删除容器类的析构函数中的向量。

答案 1 :(得分:4)

在FieldStorage析构函数中,你必须释放(以防止内存泄漏)第二种情况下为vector分配的内存。

FieldStorage::~FieldStorage()
{
    delete my_ints;
}

答案 2 :(得分:3)

正如Mykola Golubyev指出的,你需要在第二种情况下删除矢量。

第一个可能会构建更快的代码,因为优化器知道包含向量的FieldStorage的完整大小,并且可以在一个分配中为两者分配足够的内存。

您的第二个实现需要两个单独的分配来构造对象。

答案 3 :(得分:3)

我认为你真的在寻找Stack and the Heap

之间的区别

第一个在堆栈上分配,而第二个在堆上分配。

答案 4 :(得分:2)

在第一个示例中,对象在堆栈上分配。

第二个例子,对象在堆中分配,并且指向该内存的指针存储在堆栈中。

答案 5 :(得分:1)

第一种方式是使用优先级,你不需要向量上的指针而忘记删除它。

答案 6 :(得分:1)

不同之处在于第二个动态分配向量。差异很小:

  • 你必须释放向量对象占用的内存(向量对象本身,而不是向量中保留的对象,因为它由向量正确处理)。你应该使用一些智能指针来保持向量或make(例如在析构函数中):

    删除my_ints;

  • 第一个可能更有效,因为对象是在堆栈上分配的。

  • 访问vector的方法有不同的语法:)

答案 7 :(得分:1)

FieldStorage的第一个版本包含一个向量。 FieldStorage类的大小包括足以容纳向量的字节。构造FieldStorage时,向量是在FieldStorage构造函数的主体执行之前构造的。当FieldStorage被破坏时,向量也是如此。

这不一定在堆栈上分配向量;如果你堆分配一个FieldStorage对象,那么向量的空间来自那个堆分配,而不是堆栈。如果定义了一个全局FieldStorage对象,那么向量的空间既不来自堆栈也不来自堆,而是来自为全局对象指定的空间(例如某些平台上的.data.bss部分)

请注意,向量执行堆分配以保存实际数据,因此它可能只包含几个指针,或指针和几个长度,但它可能包含编译器的STL实现所需的任何内容。

FieldStorage的第二个版本包含一个指向矢量的指针。 FieldStorage类的大小包括指向矢量的指针的空间,而不是实际的矢量。您正在使用FieldStorage构造函数体中的new为向量分配存储,并且在FieldStorage被销毁时泄漏该存储,因为您没有定义删除向量的析构函数。

答案 8 :(得分:0)

在第一种情况下,std :: vector被直接放入你的类中(它正在处理任何内存分配和释放,它需要增长和缩小向量并在你的对象被销毁时释放内存;它是从您那里抽象出内存管理,这样您就不必处理它了。在第二种情况下,你明确地在堆中为std :: vector分配存储空间,并且忘记删除它,所以你的程序会泄漏内存。

答案 9 :(得分:0)

对象的大小将会有所不同。在第二种情况下,Vector&lt;&gt; *仅占用指针的大小(在32位机器上为4字节)。在第一种情况下,您的对象会更大。

答案 10 :(得分:0)

一个实际的区别在于,在第二个示例中,您永远不会释放向量的内存或其内容(因为您不删除它,因此调用它的析构函数)。

但是第一个示例会在销毁FieldStorage对象时自动销毁向量(并释放其内容)。