繁体   English   中英

这两个班级有什么区别?

[英]What's the difference between these two classes?

下面,我不是将 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;
}

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

在内存管理方面,这两个类几乎完全相同。 其他几个响应者已经建议两者之间存在差异,因为一个是在堆栈上分配存储而另一个在堆上,但这不一定是真的,即使在它是真的情况下,它也是非常误导的。 实际上,所有不同的是分配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 -它的内容-从堆中分配的,你不能改变的。

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

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

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

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

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

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

我认为你真的在寻找Stack和Heap之间的区别。

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

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

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

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

区别在于第二个动态分配向量。 差异很小:

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

    删除my_ints;

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

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

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

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

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

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

在第一种情况下,std :: vector被直接放入你的类中(它正在处理任何内存分配和释放,它需要增长和缩小向量并在对象被销毁时释放内存;它正在抽象内存来自您的管理,以便您不必处理它)。 在第二种情况下,您在某处显式为堆中的std :: vector分配存储空间,并且忘记删除它,因此您的程序将泄漏内存。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM