• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Vector i klasy, uruchamianie destruktora przy dodawaniu elementów do vectora

42 Warsaw Coding Academy
0 głosów
240 wizyt
pytanie zadane 8 kwietnia 2020 w C i C++ przez Damianek Obywatel (1,020 p.)
edycja 8 kwietnia 2020 przez Damianek

Witam,

mam dwie klasy, jedna to pojedyncze zadania, druga posiada vector, który służy do przechowywania tych zadań.

Kiedy przesyłam zadanie w celu dodania do kontenera zadań uruchamiają mi się destruktory pojedynczego zadania, chociaż przesyłam te zadania przez wskaźnik. W dodatku nie wszystkie destruktory uruchamiają się. Dlaczego tak się dzieje :)?

#include <iostream>
#include <vector>
#include <algorithm>

class Task {

public:

const char* newTask;

Task (const char* nT) : newTask(nT) { std::cout << "New Task: " << this->newTask << std::endl; }
Task () {}
~Task () { std::cout << "Destructed Task: " << this->newTask << std::endl; }

};


class Tasks {

public:

std::vector<Task>tasksContainter;

Tasks ();
~Tasks ();

void addTask (Task* t);

void show ();



};

Tasks::Tasks () {

std::cout << "New Task in Tasks" << std::endl;

}

Tasks::~Tasks () {

std::cout << "Destructed Task in Tasks" << std::endl;

}

void Tasks::addTask (Task* t) {

this->tasksContainter.push_back(*t);

}

void Tasks::show () {

for (std::vector<Task>::iterator it = this->tasksContainter.begin(); it != this->tasksContainter.end(); it++) {

std::cout << (*it).newTask << std::endl;

}


}



int main() {

std::cout << "-------------------------------------" << std::endl;
std::cout << "Creating every task" << std::endl;
std::cout << "-------------------------------------" << std::endl;

Task moveUp("moveUp");
Task moveDown("moveDown");
Task moveLeft("moveLeft");
Task moveRight("moveRight");

std::cout << "-------------------------------------" << std::endl;
std::cout << "Creating tasks container" << std::endl;
std::cout << "-------------------------------------" << std::endl;

Tasks justMoves;

std::cout << "-------------------------------------" << std::endl;
std::cout << "Before add tasks" << std::endl;
std::cout << "-------------------------------------" << std::endl;

justMoves.addTask(&moveUp);
justMoves.addTask(&moveDown);
justMoves.addTask(&moveLeft);
justMoves.addTask(&moveRight);

std::cout << "-------------------------------------" << std::endl;
std::cout << "Before show tasks" << std::endl;
std::cout << "-------------------------------------" << std::endl;

justMoves.show();

std::cout << "-------------------------------------" << std::endl;
std::cout << "End" << std::endl;
std::cout << "-------------------------------------" << std::endl;



return 0;

}

W zasadzie to podobna sytuacja zachodzi nawet przy jednej klasie:

#include <iostream>
#include <vector>
#include <algorithm>

class Task {

public:

const char* newTask;

Task (const char* nT) : newTask(nT) { std::cout << "New Task: " << this->newTask << std::endl; }
~Task () { std::cout << "Destructed Task: " << this->newTask << std::endl; }

};


int main() {

std::cout << "-------------------------------------" << std::endl;
std::cout << "Creating every task" << std::endl;
std::cout << "-------------------------------------" << std::endl;

Task moveUp("moveUp");
Task moveDown("moveDown");
Task moveLeft("moveLeft");
Task moveRight("moveRight");

std::cout << "-------------------------------------" << std::endl;
std::cout << "Creating tasks container" << std::endl;
std::cout << "-------------------------------------" << std::endl;

std::vector<Task> taskCont;

taskCont.push_back(moveUp);
taskCont.push_back(moveDown);
taskCont.push_back(moveRight);
taskCont.push_back(moveLeft);
taskCont.push_back(moveUp);

std::cout << "-------------------------------------" << std::endl;
std::cout << "Now show me" << std::endl;
std::cout << "-------------------------------------" << std::endl;

for (std::vector<Task>::iterator it = taskCont.begin(); it != taskCont.end(); it++) {

std::cout << (*it).newTask << std::endl;

}

std::cout << "-------------------------------------" << std::endl;
std::cout << "End" << std::endl;
std::cout << "-------------------------------------" << std::endl;


return 0;

}

 

3 odpowiedzi

+1 głos
odpowiedź 8 kwietnia 2020 przez adrian17 Mentor (353,220 p.)

chociaż przesyłam te zadania przez wskaźnik

To akurat nie ma wielkiego znaczenia, bo koniec końców vector i tak przechowuje kopie.

Kiedy przesyłam zadanie w celu dodania do kontenera zadań uruchamiają mi się destruktory pojedynczego zadania

Co kilka elementów, vector musi wykonać realokację, żeby móc zwiększyć swój rozmiar. Oznacza to, że dotychczasowe elementy vectora musi przekopiować do nowej lokalizacji, a ze starej lokalizacji je usunąć - czyli między innymi wywołać destruktory.

+1 głos
odpowiedź 8 kwietnia 2020 przez tangarr Mędrzec (155,180 p.)
Wektor pod spodem jest tablicą. Dane muszą być przechowywany w sposób ciągły.
Podczas dodawania nowego elementu do wektora musi on rozszerzyć swoją wewnętrzną tablicę i przenieść stare obiekty do nowego miejsca w pamięci. Potem stara kopia wektora jest usuwana (wraz z obiektami w środku).

Aby tego uniknąć masz dwa wyjścia:
1. Zarezerwować rozmiar wektora (std::vector::reserve)
2. Użyć listy (std::list) zamiast wektora
komentarz 8 kwietnia 2020 przez adrian17 Mentor (353,220 p.)

Aby tego uniknąć masz dwa wyjścia

3. przechowywać smart pointery(/wskaźniki). (IMO to też lepsze rozwiązanie od std::list)

0. nie przejmować się tym :)

komentarz 8 kwietnia 2020 przez j23 Mędrzec (195,240 p.)

4. użyć std::deque

komentarz 8 kwietnia 2020 przez Damianek Obywatel (1,020 p.)

@tangarr, Dzięki serdecznie wszystkim. Spróbowałem zarezerwować od razu miejsce na kilka elementów więcej i nie dochodzi do kopiowania. Do smart pointerów jeszcze nie doszedłem w toku nauki :). Spróbuje analogicznie z listą i kolejką.

0 głosów
odpowiedź 8 kwietnia 2020 przez mokrowski Mędrzec (158,440 p.)

1. Wektor nie będzie wykonywał realokacji elementów, jeśli będzie wiedział przed ich kreacją, ile ich może być. W tym przypadku to wiesz.

2. Zbędne będzie niszczenie tymczasowego obiektu, jeśli nakażesz jego tworzenie w pamięci std::vector a nie na zewnątrz.

W trybie minimalnych poprawek:

#include <iostream>
#include <vector>
#include <algorithm>

class Task {

public:

    const char* newTask;

    explicit Task (const char* nT) : newTask(nT) {
        std::cout << "New Task: " << this->newTask << std::endl;
    }
    ~Task () {
        std::cout << "Destructed Task: " << this->newTask << std::endl;
    }

};


int main() {

    std::cout << "-------------------------------------" << std::endl;
    std::cout << "Creating every task" << std::endl;
    std::cout << "-------------------------------------" << std::endl;
    // Zbędne bo nie uzyskujesz dostępu do obiektów w main(...)
    /*
    Task moveUp("moveUp");
    Task moveDown("moveDown");
    Task moveLeft("moveLeft");
    Task moveRight("moveRight");
    */

    std::cout << "-------------------------------------" << std::endl;
    std::cout << "Creating tasks container" << std::endl;
    std::cout << "-------------------------------------" << std::endl;

    std::vector<Task> taskCont;
    taskCont.reserve(5); // Dodaj rezerwację pamięci bo wiesz że elementów jest 5

    // Zmień konstrukcję elementu w wektorze, na emplace_back(...) tworzy to elementy
    // w zarezerwowanej pamięci std::vector
    taskCont.emplace_back("moveUp");
    taskCont.emplace_back("moveDown");
    taskCont.emplace_back("moveRight");
    taskCont.emplace_back("moveLeft");
    taskCont.emplace_back("moveUp");

    std::cout << "-------------------------------------" << std::endl;
    std::cout << "Now show me" << std::endl;
    std::cout << "-------------------------------------" << std::endl;

    for (std::vector<Task>::iterator it = taskCont.begin(); it != taskCont.end(); it++) {

        std::cout << (*it).newTask << std::endl;

    }

    std::cout << "-------------------------------------" << std::endl;
    std::cout << "End" << std::endl;
    std::cout << "-------------------------------------" << std::endl;


    return 0;

}

Jak widzisz, teraz destruktory wykonywane są tylko raz.

Podobne pytania

0 głosów
1 odpowiedź 595 wizyt
pytanie zadane 7 kwietnia 2020 w C i C++ przez Aleksandra01 Użytkownik (530 p.)
0 głosów
1 odpowiedź 626 wizyt
0 głosów
1 odpowiedź 1,272 wizyt
pytanie zadane 4 kwietnia 2017 w C i C++ przez Sidzej Użytkownik (850 p.)

93,383 zapytań

142,383 odpowiedzi

322,539 komentarzy

62,745 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

VMware Cloud PRO - przenieś swoją infrastrukturę IT do chmury
...