В чем разница между этими двумя классами? - PullRequest
2 голосов
/ 25 марта 2009

Ниже я не объявляю 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 ]

13 голосов
/ 25 марта 2009

С точки зрения управления памятью эти два класса практически идентичны. Несколько других респондентов предположили, что есть разница между двумя в том, что один выделяет хранилище в стеке, а другой - в куче, но это не обязательно так, и даже в тех случаях, когда это так, это ужасно вводит в заблуждение. В действительности все отличается от того, где выделены метаданные 1002 * для 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 - его содержимое - выделяется из кучи, и вы не можете это изменить.

Все остальные уже отметили, что у вас утечка памяти во втором примере, и это тоже правда. Обязательно удалите вектор в деструкторе вашего класса контейнера.

4 голосов
/ 25 марта 2009

Вы должны освободить (чтобы предотвратить утечку памяти) память, выделенную для вектора во втором случае в деструкторе FieldStorage.

FieldStorage::~FieldStorage()
{
    delete my_ints;
}
3 голосов
/ 25 марта 2009

Я думаю, вы действительно ищете разницу между стеком и кучей .

Первый размещается в стеке, а второй - в куче.

3 голосов
/ 25 марта 2009

Как отметил Николай Голубев, нужно удалить вектор во втором случае.

Первый, возможно, создаст более быстрый код, поскольку оптимизатор знает полный размер FieldStorage, включая вектор, и может выделить достаточно памяти в одном выделении для обоих.

Ваша вторая реализация требует два отдельных выделения для создания объекта.

2 голосов
/ 25 марта 2009

В первом примере объект размещается в стеке.

Во втором примере объект размещается в куче, а указатель на эту память сохраняется в стеке.

1 голос
/ 25 марта 2009

Первая версия FieldStorage содержит вектор. Размер класса FieldStorage включает в себя достаточно байтов, чтобы содержать вектор. Когда вы создаете FieldStorage, вектор создается непосредственно перед выполнением тела конструктора FieldStorage. Когда FieldStorage разрушен, то же самое происходит и с вектором.

Это не обязательно выделяет вектор в стеке; если вы выделяете кучу объекта FieldStorage, то пространство для вектора берется из этого выделения кучи, а не из стека. Если вы определяете глобальный объект FieldStorage, то пространство для вектора берется не из стека или кучи, а из пространства, предназначенного для глобальных объектов (например, раздел .data или .bss на некоторых платформах).

Обратите внимание, что вектор выполняет распределение кучи для хранения фактических данных, поэтому он может содержать только несколько указателей или указатель и пару длин, но он может содержать все, что требуется реализации STL вашего компилятора.

Вторая версия FieldStorage содержит указатель на вектор. Размер класса FieldStorage включает в себя место для указателя на вектор, а не фактический вектор. Вы выделяете память для вектора, используя new в теле конструктора FieldStorage, и вы теряете эту память, когда FieldStorage разрушен, потому что вы не определили деструктор, который удаляет вектор.

1 голос
/ 25 марта 2009

разница в том, что второй динамически распределяет вектор. Есть несколько отличий:

  • Вы должны освободить память, занятую векторным объектом (сам векторный объект, а не объект, сохраненный в векторе, потому что он корректно обрабатывается вектором) Вы должны использовать какой-нибудь умный указатель, чтобы сохранить вектор или сделать (например, в деструкторе):

    удалить my_ints;

  • первый, вероятно, более эффективен, поскольку объект размещен в стеке.

  • доступ к методу вектора имеет другой синтаксис:)

1 голос
/ 25 марта 2009

Первый способ предпочтителен, вам не нужен указатель на вектор, и вы забыли удалить его.

0 голосов
/ 25 марта 2009

Одно практическое отличие состоит в том, что во втором примере вы никогда не освобождаете память для вектора или его содержимое (потому что вы не удаляете его и, следовательно, вызываете его деструктор).

Но первый пример автоматически уничтожит вектор (и освободит его содержимое) после уничтожения вашего объекта FieldStorage.

0 голосов
/ 25 марта 2009

Размер объекта будет другим. Во втором случае Vector <> * занимает только размер указателя (4 байта на 32-битных машинах). В первом случае ваш объект будет больше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...