0 / 0 / 0
Регистрация: 08.11.2013
Сообщений: 51
1

Удаление объекта класса из контейнера

06.01.2015, 14:46. Показов 4095. Ответов 1
Метки нет (Все метки)

Подскажите пожалуйста как правильно удалить обьект.
C++
1
MyCarDeque.push_front(*CreateNewCar());
Так добавлял обьект в очередь.
C++
1
Car *CreateNewCar();
Функция создания нового обьекта.

Пробовал
C++
1
delete ((Car)(CarDeque[i]));MyCarDeque.pop_front();
, пишет что ожидался указатель.
Так же пробовал
C++
1
delete *((Car)(MyCarDeque[0]));MyCarDeque.pop_front();
, пишет no match for "operator*" (operand type is Car)

Так же прикрепил код из QT:
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <QCoreApplication>
#include <iostream>
#include <deque>
#include <car.h>
 
using namespace std;
 
Car *CreateNewCar();
void OutPutDeque(deque<Car> CarDeque);
 
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    deque<Car> MyCarDeque;
    int Choise=0;
 
    while(1)
    {system("cls");OutPutDeque(MyCarDeque);
 
        cout<<"\n1.Добавить новое авто в очередь.";
        cout<<"\n2.Удалить авто из очереди.";
        cout<<"\n\n>>";
 
        cin>>Choise;
 
        switch(Choise)
        {
        case 1:
            cout<<"\n1.Добавить в начало очереди.";
            cout<<"\n2.Добавить в конец очереди.";
            cout<<"\n3.Отмена.";
            cout<<"\n\n>>";
            cin>>Choise;
            switch(Choise)
            {
                case 1:MyCarDeque.push_front(*CreateNewCar());break;
                case 2:MyCarDeque.push_back(*CreateNewCar());break;
                case 3:break;
            }break;
 
        case 2:
            cout<<"\n1.Удалить из начала очереди.";
            cout<<"\n2.Удалить из конца очереди.";
            cout<<"\n3.Отмена.";
            cout<<"\n\n>>";
            cin>>Choise;
            switch(Choise)
            {
                case 1:delete *((Car)(MyCarDeque[0]));MyCarDeque.pop_front();break;
                case 2:MyCarDeque.pop_back();break;
                case 3:break;
            }break;
 
        }
    }
 
    return a.exec();
}
 
Car *CreateNewCar(){
    string name = "";
    cout<<"Name of car: ";
    while(name=="")
    {
        cin>>name;
    }
 
    double capacity=0;
    cout<<"Fuel capacity of a new car: ";
    while(capacity <= 0)
    {
        cin>>capacity;
    }
    Car *NewCar = new Car();
    NewCar->setName(name);
    NewCar->setCapacity(capacity);
 
    return NewCar;
}
 
void OutPutDeque(deque<Car> CarDeque)
{
    for(int i = 0;i<CarDeque.size();i++)
        cout<<i+1<<". Name: "<<((Car)(CarDeque[i])).getName()<<"; Fuel capacity: "
        <<((Car)(CarDeque[i])).getCapacity()<<";"<<endl;
}
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "car.h"
#include <deque>
 
Car::Car()
{
    this->capacity = 0;
    this->name = "NULL";
}
 
void Car::AddCarToDeque(deque<Car> &YourDeque, Car YourCar){
    YourDeque.push_back(YourCar);
}
 
void Car::setName(string word)
{
    this->name = word;
}
 
void Car::setCapacity(double number)
{
    this->capacity = number;
}
 
string Car::getName()
{
    return this->name;
}
 
double Car::getCapacity()
{
    return this->capacity;
}
 
 
Car::~Car()
{
 
}
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef CAR_H
#define CAR_H
 
#include <string>
#include <deque>
 
using namespace std;
 
class Car
{
 
private:
    string name;
    double capacity;
 
public:
    Car();
    ~Car();
 
    void setName(string word);
    void setCapacity(double number);
 
    string getName();
    double getCapacity();
 
    void AddCarToDeque(deque<Car> &YourDeque, Car YourCar);
};
 
#endif // CAR_H
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.01.2015, 14:46
Ответы с готовыми решениями:

Удаление объекта из контейнера
Доброго вечера... Помогите разобраться... Есть класс А: class A { }; В нем метод В: ... void...

Удаление объекта класса
Помогите с удалением объекта класса: void badstuddel(Student spis, int n) { for(int...

Удаление объекта класса SFML
проблема вот в чем. когда я удаляю объект класса программно то у меня вылетает окно SFML. #include...

Удаление поля объекта класса - corruption of the heap
в методе класса abc; for(int i=0;i&lt;5;i++) { abc temp; temp=*this;//в перегрузке...

1
541 / 162 / 79
Регистрация: 23.09.2013
Сообщений: 316
06.01.2015, 16:35 2
Судя по предоставленному коду, внутри деки вы храните сами объекты типа Car:
C++
1
deque<Car> MyCarDeque;
При этом создаёте объект машины в куче при помощи функции:
C++
1
Car *CreateNewCar();
Проблема заключается в том, что вызов:
MyCarDeque.push_front(*CreateNewCar());
Сделает следующее
1) Создаст в куче объект машины, вернет из функции CreateNewCar() указатель на этот объект.
2) Разыменование (*CreateNewCar()) rvalue указателя даст доступ к объекту машины
3) Будет взята константная ссылка на объект, которая будет передана методу push_front
4) Метод push_front создаст в деке копию объекта, переданного по константной ссылке.
Пруф: http://www.cplusplus.com/refer... ush_front/
Цитата: "Inserts a new element at the beginning of the deque container, right before its current first element. The content of val is copied (or moved) to the inserted element."
Вольный перевод: Вставляет новый элемент в начало контейнера дек, сразу до первого элемента дека. Значение переменной val будет копировано (или перемещено) во вставляемый элемент.

Таким образом:
1) Утечка памяти из-за не удаленного объекта, выделенного в куче
2) Не возможность удалять объекты из дека оператором delete, поскольку дек управляет своим содержимым, а в данном случае - содержимое - объекты типа Car.

Возможные решения:
1) Изменить метод Car *CreateNewCar(); так, чтобы он возвращал копию созданного объекта Car, который бы создавался на стеке. (Новая сигнатура функции выглядела бы Car CreateNewCar(); ключевое слово new внутри метода для создания объекта не использовалось бы)
2) Изменить дек deque<Car> MyCarDeque; так, чтобы он содержал не сами объекты типа Car, а указатели на объекты типа Car: deque<Car *> MyCarDeque; Далее, вручную с помощью delete удалять объекты, которые в деке больше присутствовать не будут
2.1) Изменить дек deque<Car> MyCarDeque; так, чтобы он хранил умные указатели на объекты типа Car, которые бы освобождали память под объекты как только данный указатель удален из дека.
deque<std::unique_ptr<Car> > MyCarDeque;

Добавлено через 4 минуты
На тему Вашего прямого вопроса, как удалить при помощи delete объект, находящийся в деке:
C++
1
delete &deque[0];
Получаем первый элемент, далее с помощью операции & - берем адрес этого элемента, delete - получает корректное значение с типом Car* указывающим на 0-й элемент в деке.
Такая запись успешно скомпилируется, но приведет к ошибке времени исполнения из-за двойного удаления элемента из дека. Равносильно тому же что и :
C++
1
2
Car car;
delete &car;
Добавлено через 1 час 3 минуты
Позволю себе небольшое отступление от темы, маленький код ревью для Вас:
C++
1
2
3
4
5
6
void OutPutDeque(deque<Car> CarDeque)
{
    for(int i = 0;i<CarDeque.size();i++)
        cout<<i+1<<". Name: "<<((Car)(CarDeque[i])).getName()<<"; Fuel capacity: "
        <<((Car)(CarDeque[i])).getCapacity()<<";"<<endl;
}
Этот кусочек кода содержит множество проблем, я постараюсь описать наиболее очевидные.
Проблемы трех типов:
1) Используемые ресурсы
2) Смысловая нагрузка
3) Читаемость

Итак используемые ресурсы:
1.1) Проблема: Передача void OutPutDeque(deque<Car> CarDeque) по значению приведет к тому, что при каждом вызове метода, будет создаваться локальная копия дека. Представьте что там хотя бы тысяча машин, и на каждую машинку тратится хотя бы 20 байт памяти - это уже + 20 000 байт на время выполнения тела метода
Решение: Использовать передачу по константной ссылке - ссылка на объект в зависимости от реализации в компиляторе будет использовать объем памяти сопоставимый с размером одного указателя. void OutPutDeque(const deque<Car> &CarDeque);

1.2) Проблема: вывод на экран информации при помощи cout является длительной операцией. С учетом того, что вызов происходит в цикле - на большом количестве машин можно будет наблюдать достаточно серьёзные проблемы с производительностью. Кроме того, дело усугубляется передачей endl в поток на каждой итерации. Это приводит не только к добавлению новой строки, но и вызову flush, что дополнительно тормозит систему.

Возможное решение: использовать '\n' для перевода на новую строку, вместо endl, формировать полный отчет о машинах в памяти, после чего целиком копировать его в поток вывода.

1.3) Проблема: CarDeque.size(), вызываемый в цикле. В данном случае не представляет большой проблемы, поскольку время получения размера дека гарантированно константным, но может в принципе сыграть плохую службу при замене контейнера с дека на лист. В общем случае - метод вызывается столько раз, сколько элементов в деке находится. Поскольку обход в цикле осуществляется с первого до последнего элементов.

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

1.4) Проблема: использование i++ - постфиксного инкремента на итераторе. В данном случае, поскольку в роли итератора выступает целочисленная переменная - большой угрозы не несет, но при использовании итераторов из дека - такая привычка будет приводить к потере производительности. Суть проблемы в том, что для поддержания способа работы постфиксного инкремента (с одной стороны изменить значение переменной, с другой - вернуть результат до изменения) - требуется создание локальной копии элемента. В общем случае - создание локальной копии требует дополнительных затрат времени и ресурсов.

Решение: Использовать префиксный инкремент везде, где явным образом не требуется функциональность постфиксного инкремента.

1.5) Проблема: использование типа int в качестве типа для итератора по элементам дека. Суть проблемы в том, что для выражения размера дека используется без знаковая целочисленная переменная, при этом - int - тип знаковый. Если в деке будет достаточно много элементов, знаковый int переполнится, и будет иметь большие отрицательные значения.

Решение: в общем случае использовать либо без знаковый вариант целочисленной переменной unsigned int; Либо использовать специальный тип size_t используемый для работы с размерами.

1.6) Проблема: универсальность использования функции понижена из-за того, что используется глобальная переменная cout вместо универсального потока. Делает невозможным тестирование, усложняет отладку.

Решение: передавать в качестве аргумента поток, в который будет транслироваться информация, которая в данный момент попадает в cout.

2.1) OutPutDeque - является плохим названием для данной функции. С одной стороны - output "Выход, мощность, выпуск" - слово имеющее достаточно косвенное отношение к том, что же на самом деле происходит в функции. С другой стороны - нет конкретизации того, что информация будет выведена на экран, показана пользователю. С другой стороны - Deque - является характеристикой детали реализации - Вы решили использовать дек для хранения элементов машин, а завтра выяснится, что нужно использовать вектор, или лист - и тогда название этой функции вообще перестанет отражать действительность.

Решение: Использовать более явные глаголы для характеристики производимых действий (ShowToUser - как пример) (но без конкретизации на том как именно они будут осуществляться) В дополнение к этому использовать существительное, характеризующее ту сущность, с которой будут производиться действия и которая требуется в качестве аргумента функции. (Cars или CarsInfo - как пример). Тогда функция выглядела бы согласованно void ShowCarsInfoToUser(const deque<Car> cars);

2.2) Проблема: Внутри метода используется вывод в cout некоторой информации о машине. При этом данный вывод реализован прямо на месте и не выделен в отдельную функцию

Решение: Выделить метод формирования информации об автомобиле в отдельную функцию, принимающую в качестве аргумента автомобиль, и возвращающую строку с информацией об автомобиле. Это может быть свободная функция, либо метод самого класса Car, типа car.Info();

3.1) Проблема: плохое форматирование кода. Во-первых цикл не являющийся тривиальным не имеет скобок {}. Это может способствовать внесению ошибок при попытке изменений (например добавления второй строки с действиями, в ожидании, что добавленные строки будут использоваться в теле цикла, а не однократно). Во-вторых вывод в cout не разбит на логические блоки, в итоге читается как кашеобразная запись.

Решение: форматировать код ( не уверен, что форум позволит передать правильную упорядоченность символов - в общем по левому краю << должны быть один под другим.
C++
1
2
3
4
5
6
  
  for (int i = 0; i < CarDeque.size(); i++) {
    cout << i + 1 << ". Name: " << ((Car)(CarDeque[i])).getName()
           << "; Fuel capacity: " << ((Car)(CarDeque[i])).getCapacity() << ";"
           << endl;
  }
3.2) Проблема: Избыточный, повторяющийся и не читаемый код ((Car)(CarDeque[i])).getName() и ((Car)(CarDeque[i])).getCapacity()
С одной стороны - из-за обращения внутри цикла - два раза используется взятие i-го элемента, что является повторением, с другой стороны - для чего-то тип элемента приводится к типу Car. Наконец куча излишних скобок,

Решение: убрать дублирующиеся и избыточные элементы.

3.3) Проблема: использование "сырого" цикла, в месте обхода всех элементов контейнера. Добавляет возможность ошибки, дополнительный код - больше писанины, вынуждает обращаться к элементам по индексу.

Решение: использование range base loop:
for(const auto &car : cars) {
car.getName();
}

3.4) Проблема: Использование конвенций именования. Предполагаю, что Вами не использовалась конвенция именования, либо она разительно отличается от используемой мной. (google code style)

Подводя итог, я представляю поверхностно исправленную версию Вашего кода:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <deque>
#include <iostream>
 
class Car {
public:
  std::string Name() const { return std::string(); }
 
  double Capacity() const { return 42.; }
 
  std::string Info() const {
    return "Name: " + Name() + "; Fuel capacity: " + std::to_string(Capacity());
  }
};
 
void ShowCarsInfoToUser(const std::deque<Car> &cars,
                        std::ostream &user_stream) {
  size_t number_of_car = 1;
  for (const auto &car : cars) {
    user_stream << number_of_car++ << " " << car.Info() << ";\n";
  }
}
 
int main() {
  std::deque<Car> cars;
  ShowCarsInfoToUser(cars, std::cout);
}
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.01.2015, 16:35
Помогаю со студенческими работами здесь

Как вызвать метод объекта из контейнера?
Есть абстрактный класс E, производный от CObject, в нем чистая виртуальная войдовская функция....

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

Удаление элемента из контейнера и итераторы
Кто знает при удалении элемента из контейнера через итератор, этот итератор становится...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru