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

возьмите простой класс с " big 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.

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

8 ответов


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

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

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

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


для вашей информации, вот как вы это сделаете:

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
    }
};

но не забудьте оператор copy-assignment. Я рекомендую идиома копирования и замены, и оставьте это как упражнение для вас.

(помните, что вы не вообще-то нужна.)


"большая тройка" - это не то, что вы говорите. Это: конструктор копирования, оператор назначения копирования и деструктор.

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

ваш конструктор копирования неверен, он не копирует исходные векторы в новый класс, он просто создает из них локальные функции которые затем отбрасываются. Это создает локальные переменные с именем 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)
{
}

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


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


ваш класс также может быть упрощен:

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 знает, как правильно выполнять все три операции, и поэтому вам не нужно добавлять дополнительный код.


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


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


а не newЭд mass, вам не нужно удалять его.

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


  ~planets(){ 
     mass.clear();
     radius.clear();
  } 

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