Search code examples
c++smart-pointersfactory-pattern

C++ Factory Pattern with Smart Pointers - can't get past "use of deleted function" error


I'm attempting to make a small C++ Factory Pattern example with smart pointers. Here is what I have so far:

// FactorySmart.cpp

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

enum AnimalSpecies { dog, cat };

class Animal
{
public:
  virtual void makeSound() = 0;
};

class Dog : public Animal
{
public:
  void makeSound() { std::cout << "woof" << "\n\n"; }
};

class Cat : public Animal
{
public:
  void makeSound() { std::cout << "meow" << "\n\n"; }
};

class AnimalFactory
{
public:
  static std::unique_ptr<Animal> makeAnimal(AnimalSpecies animalSpecies);
};

std::unique_ptr<Animal> AnimalFactory::makeAnimal(AnimalSpecies animalSpecies)
{
  if (animalSpecies == AnimalSpecies::dog)
  {    
    return(std::make_unique<Dog>());   
  }
  else if (animalSpecies == AnimalSpecies::cat)
  {    
    return(std::make_unique<Cat>());    
  }
  else
  {
    std::cout << "error in AnimalFactory::makeAnimal(), animalSpecies = " << animalSpecies << " does not seem to be valid" << "\n\n";
    return(nullptr);
  }
}

int main(void)
{  
  std::vector<std::unique_ptr<Animal>> animals;

  std::unique_ptr<Animal> dog = AnimalFactory::makeAnimal(AnimalSpecies::dog);
  animals.push_back(dog);

  std::unique_ptr<Animal> cat = AnimalFactory::makeAnimal(AnimalSpecies::cat);
  animals.push_back(cat);

  for (auto &animal : animals)
  {
    animal->makeSound();
  }

  return(0);
}

With GCC 7.3 I get:

error: use of deleted function

With the Microsoft compiler that ships with Visual Studio 2019 I get:

attempting to reference a deleted function

If I comment out these lines the error goes away, so it would seem this is where I'm going wrong:

std::unique_ptr<Animal> dog = AnimalFactory::makeAnimal(AnimalSpecies::dog);
animals.push_back(dog);

std::unique_ptr<Animal> cat = AnimalFactory::makeAnimal(AnimalSpecies::cat);
animals.push_back(cat);

I've looked at very similar examples on Stack Overflow and elsewhere and I can't seem to work out where I'm going wrong. Suggestions please?

--- EDIT ---

After changes per Kit's accepted answer below, here is a complete working copy/pastable example:

// FactorySmart.cpp

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

enum AnimalSpecies { dog, cat };

class Animal
{
public:
  virtual void makeSound() = 0;
};

class Dog : public Animal
{
public:
  void makeSound() { std::cout << "woof" << "\n\n"; }
};

class Cat : public Animal
{
public:
  void makeSound() { std::cout << "meow" << "\n\n"; }
};

class AnimalFactory
{
public:
  static std::unique_ptr<Animal> makeAnimal(AnimalSpecies animalSpecies);
};

std::unique_ptr<Animal> AnimalFactory::makeAnimal(AnimalSpecies animalSpecies)
{
  if (animalSpecies == AnimalSpecies::dog)
  {
    std::unique_ptr<Animal> dog = std::make_unique<Dog>();
    return(dog);
  }
  else if (animalSpecies == AnimalSpecies::cat)
  {
    std::unique_ptr<Animal> cat = std::make_unique<Cat>();
    return(cat);
  }
  else
  {
    std::cout << "error in AnimalFactory::makeAnimal(), animalSpecies = " << animalSpecies << " does not seem to be valid" << "\n\n";
    return(nullptr);
  }  
}

int main(void)
{
  std::vector<std::unique_ptr<Animal>> animals;

  std::unique_ptr<Animal> dog = AnimalFactory::makeAnimal(AnimalSpecies::dog);
  animals.push_back(std::move(dog));

  std::unique_ptr<Animal> cat = AnimalFactory::makeAnimal(AnimalSpecies::cat);
  animals.push_back(std::move(cat));

  for (auto &animal : animals)
  {
    animal->makeSound();
  }  

  return(0);
}

Solution

  • In your animals.push_back(), you are trying to make a copy of the unique_ptr<>, which is not allowed.

    Instead, use:

    std::unique_ptr<Animal> dog = AnimalFactory::makeAnimal(AnimalSpecies::dog);
    animals.push_back(std::move(dog));
    
    std::unique_ptr<Animal> cat = AnimalFactory::makeAnimal(AnimalSpecies::cat);
    animals.push_back(std::move(cat));
    

    Then the dog and cat will release their pointers and won't delete the objects when the destructors of the smart pointers are called.