Векторы внутри классов: обработка конструктора и деструктора копирования (C ++)

Возьмем простой класс с "большой 3" (конструктор, конструктор копирования, деструктор):

#include <vector>
using namespace std; //actually goes in the C file that links to this header file
...
class planets(){ //stores mass and radii data for planets in a solar system.
   public:
      vector <double> mass;
      vector <double> radius;

   //constructor
   planets( int numObj ){
     for(int i=0; i<numObj; i++){
         mass.push_back(8.0); //some default values.
         radius.push_back(2.0);
     }
   }
   //copy constructor
   planets(const planets &p){
      vector <double> mass(p.mass); //copy vectors into new class.
      vector <double> radius(p.radius);
   }
  //destructor
  ~planets(){
     delete mass; //ERROR: (...) argument given to ‘delete’, expected pointer
     ~radius(); //also causes error: no match for call to(...) 
   }
}

Я планирую создать вектор планет, таким образом, потребность в "большой 3":

vector <planets> stars;
stars.push_back(planets(5)); //5 hypothetical planets of alpha centauri
stars.push_back(planets(8)); //our solar system. Used to be nine.
///etc.

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

12
задан James McNellis 31 January 2011 в 03:26
поделиться

8 ответов

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

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

Причина, по которой вам нужна большая тройка, записанная в управляющем классе, заключается в том, что специальные члены по умолчанию обычно делают неправильные вещи (они копируют, присваивают, уничтожают значения вместо того, на что значения управляют / на что указывают). Но как только вы ресурс завернут (как в std :: vector ), все в порядке. По умолчанию копируется вектор, , но , что копирование написано правильно.

Кстати, Большая тройка в контексте управления ресурсами (копирование и уничтожение ресурсов), а не их создания. Таким образом, это будет конструктор копирования, присваивание копии и деструктор, а не конструктор по умолчанию.


К вашему сведению, вот как вы это сделаете:

class planets
{
public:
    // ...

    //copy constructor
    planets(const planets &p) : // use an initialization list to initialize
    mass(p.mass), // copy-construct mass with p.mass
    radius(p.radius) // copy-construct radius with p.radius
    {
        // what you had before just made a local variable, copy-constructed
        // it with p.xxx, then got released (nothing happened to your members)
    }

    //destructor
    ~planets()
    {
        // nothing to do, really, since vector destructs everything 
        // right for you, but you yes, you would delete any resources
        // you managed here
    }
};

Но не забывайте об операторе копирования-присваивания. Я рекомендую идиому копирования и обмена и оставляю это вам в качестве упражнения.

(Однако помните, что на самом деле они вам не нужны.)

23
ответ дан 2 December 2019 в 04:25
поделиться

Вам не нужно реализовывать деструктор для вашего класса. Векторы будут автоматически уничтожены. Это связано с шаблоном Инициализация получения ресурсов .

4
ответ дан 2 December 2019 в 04:25
поделиться

В вашей конкретной ситуации вам не нужно! Вы не храните указатели в векторе. Вы не храните указатели на векторы в своем классе планет (то есть вы не выделяли объект vector <> динамически, так зачем пытаться его удалить).

0
ответ дан 2 December 2019 в 04:25
поделиться
  ~planets(){ 
     mass.clear();
     radius.clear();
  } 

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

-1
ответ дан 2 December 2019 в 04:25
поделиться

«Большая тройка» - не то, о чем вы говорите. Это: конструктор копирования, оператор присваивания копии и деструктор.

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

Ваш конструктор копирования неверен, он не копирует исходные векторы в новый класс, он просто создает из них локальные переменные функции, которые затем отбрасываются. Это создает локальные переменные с именами mass и radius , которые маскируют переменные-члены с тем же именем.

planets(const planets &p){
  vector <double> mass(p.mass); //copy vectors into new class.
  vector <double> radius(p.radius);
}

Более правильным (но ненужным) было бы:

planets(const planets &p)
  : mass(p.mass) //copy vectors into new class.
  , radius(p.radius)
{
}

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

5
ответ дан 2 December 2019 в 04:25
поделиться

Поскольку вы не новую ed массу , вам не нужно удалять ее.

Кроме того, деструкторы массы и радиуса будут вызываться автоматически, вам не нужно вызывать их явно

0
ответ дан 2 December 2019 в 04:25
поделиться

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

1
ответ дан 2 December 2019 в 04:25
поделиться

Ваш класс тоже можно упростить:

class planets()
{ //stores mass and radii data for planets in a solar system.
  public:
    std::vector<double> mass;
    std::vector<double> radius;

  //constructor
  planets( int numObj )
  {
    for(int i=0; i<numObj; i++)
    {
      mass.push_back(8.0); //some default values.
      radius.push_back(2.0);
    }
  }
}

Ваш класс не содержит ресурсов (т.е. указателей)
. Поэтому вам не нужно явно управлять ими. Каждый класс должен уметь:

  • Копировать себя
  • Быть присвоенным
  • Уничтожить себя

Оператор присвоения конструктора копирования и деструктор, созданные компилятором, автоматически вызовут эти операции над любыми переменными-членами (масса и радиус), так что вам это не нужно. Таким образом, в вашем случае std::vector знает, как правильно выполнить все три операции, и поэтому вам не нужно добавлять дополнительный код.

2
ответ дан 2 December 2019 в 04:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: