Нужно ли удалять этот объект? (если я не собираюсь когда-либо удаляться)

0

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

void  gShop::CreateCustomer(int type, int number)
    {
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
    }

где vSlot - вектор указателей на объекты клиента. У меня есть (здесь: сокращенный) класс gShop, по существу:

class gShop : public gBranch
   {
   public:
       gShop(): vSlot(100){}
      ~gShop(){}   

       std::vector <gCustomer*>   vSlot;
       ...
   }

и в основном я вызываю функцию-член для создания новых клиентов.

  vShop[0].CreateCustomer(TYPE_M20, 1);
  vShop[0].CreateCustomer(TYPE_F40, **2**);//EDIT:typo previously here. I intend to create customers by reading a file later on.

  std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
  std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

Я знаю, что я создал с "новыми" двумя объектами в "куче" (если я правильно отношусь к терминологии - извините, я совершенно новичок в программировании без формального образования), и у меня также есть два указателя на объекты, хранящиеся в векторе внутри магазин объектов [0].

Мой вопрос: я слышал высказывание, что для каждого нового есть удаление. Где я должен удалить этот объект? На самом деле я не планирую удалять какой-либо созданный магазин или объект клиента в программе.

Во-вторых, этот код до сих пор хорошо подходит для того, чтобы не вызывать утечки памяти? Я немного обеспокоен тем, что создал новый объект в классе функций-членов, поэтому я должен попытаться реализовать delete в деструкторе в gShop и установить указатель на NULL - в теоретическом случае я должен когда-либо захотеть удалить магазин [0]?

Большое спасибо.

Теги:
memory-leaks
heap

4 ответа

0
Лучший ответ

Каждый раз, когда вы создаете объект с new куском памяти, берется из кучи. Единственный способ связаться с этой памятью - это указатель, который вы получили от new. Когда вы используете delete эта память указателя освобождается и может использоваться для других целей. Поэтому, когда вы теряете указатель, вы создаете утечку памяти.
В вашем коде правильный путь:
Начните с вектора с нулевыми указателями. Когда вы создаете объект в точном указателе проверки позиции. Если он не является нулевым, у вас уже есть объект и его нужно удалить (или, возможно, выполнить ошибку)

void  gShop::CreateCustomer(int type, int number)
{
    if(vSlot[number] != 0) {
         delete vSlot[number];
         vSlot[number] = 0;
    }
    vSlot[number] = new gCustopmer(type);
    vSlot[number]->itsContactToShop=itsShopNumber;
    vSlot[number]->itsNumber=number;
}

Когда вектор уничтожается, вам нужно освободить всю память внутри него. Таким образом, у вас деструктор будет что-то вроде этого:

gShop::~gShop() {
    for(int i = 0; i < (int)vSlot.size(); ++i) {
          delete vSlot[i];
    }
}
  • 0
    Это классно. То есть вы имеете в виду vSlot (100, NULL) вместо vSlot (100)? И затем я заменяю его проверкой на утверждение if, если оно NULL, как вы показали?
  • 0
    никакие векторы уже не инициируют его с нулями. Но когда у вас есть сырые поля, вы должны начинать их с нуля (это хороший способ написать). Извините за ошибки (и правильный ответ) в создании функции. Вы проверяете, существуют ли указатели, а не нулевые объекты.
Показать ещё 11 комментариев
3

В том, как вы написали свой код, вы должны расширить реализацию деструктора для gShop чтобы gShop vector<> vSlot и delete каждый элемент. Поскольку у вас есть память, которая должна управляться таким образом, чтобы предотвратить утечку памяти, вам также необходимо следовать правилу 3. Таким образом, вам также нужно что-то сделать во время создания копии (глубокая копия), и вам нужно что-то сделать для оператора присваивания (очистить vector<> который скоро будет скопирован, и сделать глубокую копию).

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

    std::vector<std::shared_ptr<gCustomer>> vSlot;

Когда вы создаете элемент в vSlot, вы можете использовать make_shared():

    vSlot[number] = std::make_shared<gCustopmer>(type);

Умный указатель удалит память для вас, когда больше нет ссылок на память. Если у вас нет доступных C++.11, вместо этого вы можете использовать boost::shared_ptr.

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

Если вы хотите что-то, что будет автоматически очищаться, как смарт-указатель, но все равно дадите вам глубокую копию с конструктором копии по умолчанию и оператором присваивания по умолчанию, вы можете попробовать использовать boost::optional.

Если вы используете g++ версии 4.4 или выше, то вы должны иметь возможность включить функции C++.11 с помощью -std=gnu++0x или -std=C++0x если вы не хотите Расширения GNU. Если у вас есть g++ 4,7 или выше, то это опции -std=gnu++11 или -std=C++11.

  • 0
    Вы должны исправить >> до > > . Кроме того, хорошая работа по упоминанию глубокого копирования.
  • 0
    @Cramer Нечего исправлять. std::shared_ptr - это C ++ 11, поэтому закрытие нескольких шаблонов подряд без пробелов >> вполне нормально.
Показать ещё 5 комментариев
0

gShop необходимо delete объекты gCustomer которые он создает. Он может сделать это в своем деструкторе, например:

class gShop : public gBranch
{
public:
    ...
    ~gShop()   
    ...
};

gShop::~gShop()
{
    std::vector<gCustomer*>::iterator iter = vSlot.begin();
    std::vector<gCustomer*>::iterator end = vSlot.end();
    while (iter != end)
    {
        delete *iter;
        ++iter
    }
}

Или:

void deleteCustomer(gCustomer *customer)
{
    delete customer;
}

gShop::~gShop()
{
    std::for_each(vSlot.begin(), vSlot.end(), deleteCustomer);
}

Однако вы все равно будете иметь утечку памяти. Вы сохраняете два отдельных объекта gCustomer в одном и том же vSlot[1] vShop[0], поэтому вы теряете vShop[0] над одним из ваших клиентов. Я подозреваю, что вы хотели сделать это вместо этого:

vShop[0].CreateCustomer(TYPE_M20, 1);
vShop[0].CreateCustomer(TYPE_F40, 2); // <-- was previously 1

std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
std::cout<< "2" << vShop[0].vSlot[2]->itsTypeString << std::endl;

При этом вам следует подумать о своем дизайне и позволить STL обрабатывать все управление памятью для вас, например:

class gShop : public gBranch
{
public:
    std::vector <gCustomer> vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    vSlot.push_back(type);
    gCustomer &cust = vSlot.back();
    cust.itsContactToShop = itsShopNumber;
    cust.itsNumber = vSlot.size()-1;
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);


// remember that vectors are 0-indexed
std::cout<< "0" << vShop[0].vSlot[0].itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1].itsTypeString << std::endl;

Или:

class gShop : public gBranch
{
public:
    std::vector <std::shared_ptr<gCustomer> > vSlot;
    ...
};

void gShop::CreateCustomer(int type)
{
    std::shared_ptr customer = std::make_shared<gCustomer>(type);
    customer->itsContactToShop = itsShopNumber;
    customer->itsNumber = vSlot.size();
    vSlot.push_back(customer);
}

vShop[0].CreateCustomer(TYPE_M20);
vShop[0].CreateCustomer(TYPE_F40);

std::cout<< "0" << vShop[0].vSlot[0]->itsTypeString << std::endl;
std::cout<< "1" << vShop[0].vSlot[1]->itsTypeString << std::endl;
  • 0
    да, должно было быть "2" - моя ошибка при наборе текста. Я также на самом деле не хочу удалять какой-либо элемент vSlot, так как я скорее заполняю их «фиктивными» клиентами. Я не получил shared_ptr? Это новый синтаксис C ++? Я начал всю программу несколько лет назад со старой версии вместе с OpenGL. Он имеет несколько тысяч строк кода. Я застрял с этой версией, я верю и не могу использовать shared_ptr.
  • 0
    shared_ptr является новым в C ++ 11. Для более старых версий C ++ вместо этого вы можете использовать boost::shared_ptr .
Показать ещё 1 комментарий
0

Да, любая память, выделенная из кучи, должна быть освобождена! С "новым" вы выделяете память из кучи, которая является sizeof gCustomer. Хорошее место для освобождения вашей памяти будет в вашем деструкторе: ~ gShop() Утечки памяти вызваны не освобождением памяти, хотя после того, как вы закроете свою программу, вся память будет автоматически освобождена.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню