I have implemented to following generic factory in C++11 using smart pointers and I would like to get some feedback about it.
(Please note that I can't use C++14)
Due to company policies I have to change the names of the business objects.
class Car{};
class Taxi : public Car{};
class Police : public Car{};
class CarFactory {
public:
enum CarName {TaxiName, PoliceName};
std::unique_ptr<Car> getCar(CarName sa) {
if (d_carMap.find(sa) == d_carMap.end()) {
d_carMap[sa] = std::move(createCar(sa));
}
return std::move(d_carMap[sa]);
}
private:
std::unordered_map<CarName,
std::unique_ptr<Car>,
std::hash<int>> d_carMap; //hash is for enum
std::unique_ptr<Car> createCar(CarName sa) {
if (sa == CarName::TaxiName){
return std::unique_ptr<Car>(new Taxi());
} else if (sa == CarName::PoliceName) {
return std::unique_ptr<Car>(new Police());
}
return nullptr; //no car found for provided argument.
}
};
- Which of the moves are actually needed here?
- What happens to the
unique_ptr
s, if this factory is used in a multi threading environment? - Is
std::unique_ptr<Car>(new Taxi());
really the best way of instantiating a smart pointer in C++11 (which doesn't have make_unique)? - Should the enum be a class, even if I can't use std::hash on it?
- Where would you define the enum? In a separate header file? In the same header, outside of the class (but in a namespace)?
- How should the unit test look like?
I wrote the following test which actually fails on the indicated line:
TEST(CarFactoryTest, retrieveTaxi) {
CarFactory sf;
auto Car = sf.getCar(CarFactory::CarName::TaxiName);
if (!Car) {
FAIL();
}
if (dynamic_cast<Taxi*>(Car.get()) == nullptr) {
FAIL();
}
//this time get it from the map
Car = sf.getCar(CarFactory::CarName::TaxiName);
if (!Car) {
FAIL(); //Test fails here!
}
if (dynamic_cast<Taxi *>(Car.get()) == nullptr) {
FAIL();
}
}