unique_ptrs и преобразованные указатели и вектор

Я создал абстрактный класс, а затем создал дочерние классы, которые наследуют этот абстрактный класс.

  class A{
       public:
       virtual A* clone() const = 0;
       virtual A* create() const = 0;
       ~virtual A(){};
       // etc.

  };

дочерние классы

     class B: public A{};
     class C: public A{};

Затем я использую неявное преобразование указателя дочернего класса в указатель базового класса в основной функции.

     int main(){

     B* pB = new B();
     C* pC = new C();

     A* pA = pB;     //converting a pointer to A, to a pointer to B
     A* pAA = pC;    //converting a pointer to A, to a pointer to C

Теперь я могу заполнить вектор этими классами, используя указатель типа A, и получить доступ к дочерним классам с помощью полиморфизма.

    vector<A*> Pntr;

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

Если я закодирую это так:

    pA = unique_ptr<A>(pB);
    pAA = unique_ptr<A>(pC);

Затем я заполняю вектор следующим образом:

    vector<unique_ptr<A>>Pointers;
    Pointers.push_back(move(pA));
    Pointers.push_back(move(pAA));

Не уверен, что это даже сработает. И я также смущен тем, что он будет фактически уничтожен, когда вектор выйдет за рамки. Будут ли преобразованные указатели pA и pAA просто установлены в NULL или объекты класса будут уничтожены - что является моим первоначальным намерением. Нужна некоторая ясность.


person A Big Ball Of Lettuce    schedule 17.07.2015    source источник
comment
Мне кажется, все в порядке. Почему бы не попробовать?   -  person Lightness Races in Orbit    schedule 17.07.2015
comment
Как я ответил на ваш предыдущий вопрос, объекты класса будут уничтожены. Однако вы не можете назначить unique_ptr необработанному указателю, что, похоже, вы и делаете.   -  person Barry    schedule 17.07.2015
comment
Спасибо за все ваши ответы на этот и мой предыдущий вопрос. Я пробую это прямо сейчас, за исключением того, что мне приходится использовать auto следующим образом: auto pA = unique_ptr‹A›(pB);   -  person A Big Ball Of Lettuce    schedule 17.07.2015


Ответы (1)


Почему бы тебе просто не попробовать это сделать?

В приведенном ниже примере представлен способ создания Interface (вашего абстрактного базового класса) и двух производных классов, реализующих этот интерфейс (в данном случае Foo и Bar).

Затем вы можете создать контейнер std::unique_ptr<Interface> (уникальные указатели на абстрактный базовый класс) и заполнить его, используя различные методы и вспомогательные функции: emplace_back с std::make_unique, push_back с std::move и так далее.

После запуска примера вы заметите, что деструктор вызывается автоматически — в этом прелесть std::unique_ptr.

#include <cassert>
#include <memory>
#include <vector>
#include <iostream>

class Interface {
 public:
  virtual ~Interface() {
    std::cout << "Destroying object" << std::endl;
  }
  virtual void Method() const = 0;
};

class Foo // Foo "implements" or "offers access to" the Interface
    : public Interface {
 public:
  void Method() const override { // here we override Interface::Method
    std::cout << "Foo::Method" << std::endl;
  }
};

class Bar // Bar "implements" or "offers access to" the Interface
    : public Interface {
 public:
  void Method() const override { // here we override Interface::Method
    std::cout << "Bar::Method" << std::endl;
  }
};


int main() {
  // declare
  std::vector<std::unique_ptr<Interface>> objects;

  // populate
  objects.emplace_back(std::make_unique<Foo>());
  objects.emplace_back(std::make_unique<Bar>());
  objects.emplace_back(std::make_unique<Foo>());

  // another way to populate
  std::unique_ptr<Foo> pfoo(new Foo);
  objects.push_back(std::move(pfoo));

  // but be careful... pfoo now points to nullptr because you
  // moved ("transfered control of") the pointer to the
  // vector; pfoo no longer owns it (so it owns nothing; it is a
  // nullptr)
  assert(pfoo == nullptr);

  // you can iterate over all members by REFERENCE (otherwise you
  // would need to make copies, and you cannot copy a unique_ptr)
  for(const auto & pobject : objects) {
    pobject->Method();
  }

  // at exit you should see the calls to the destructor

  return 0;

}

Скомпилируйте и запустите:

$ g++ example.com -std=c++14 -Wall -Wextra
$ ./a.out
Foo::Method
Bar::Method
Foo::Method
Foo::Method
Destroying object
Destroying object
Destroying object
Destroying object
person Escualo    schedule 17.07.2015