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