How to use make_shared for making the instance of singleton class. Instantiating singleton class gives error.

Hi ppl :),

I am trying to make instance of singleton class using make_shared. Getting error while instantiating the singleton class.
Kindly note that if we change the instance pointer from shared_ptr to raw pointer, animalFactory = new AnimalFactory(), program works well.

I am trying using the below code, but getting the following error :


animal_factory.cpp:22:61:   required from here
/usr/include/c++/6/ext/new_allocator.h:120:4: error: ‘AnimalFactory::AnimalFactory()’ is private within this context
  { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
animal_factory.cpp:3:1: note: declared private here
 AnimalFactory::AnimalFactory()



animal_factory.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#ifndef ANIMAL_FACTORY_H_
#define ANIMAL_FACTORY_H_

#include "animal_prototype.h"
#include "cat_prototype.h"
#include "snail_prototype.h"
#include <map>
#include <string>
#include <memory>
#include <mutex>

class AnimalFactory
{
    private:
        AnimalFactory();
        AnimalFactory(const AnimalFactory &);
        AnimalFactory& operator=(const AnimalFactory&);
        static std::shared_ptr<AnimalFactory> animalFactory;
        typedef std::map<std::string, std::unique_ptr<AnimalPrototype> > AnimalFactoryMap;
        AnimalFactoryMap myMap;
        static std::recursive_mutex mtx;

    public:
        virtual ~AnimalFactory();
        static std::shared_ptr<AnimalFactory> getAnimalFactory();
        std::unique_ptr<AnimalPrototype> getAnimal(const std::string &);
};

#endif 



animal_factory.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include "animal_factory.h"

AnimalFactory::AnimalFactory()
{
    myMap["cat"] = std::make_unique<CatPrototype>();
    myMap["snail"] = std::make_unique<SnailPrototype>();
}
AnimalFactory::AnimalFactory(const AnimalFactory &) {}
AnimalFactory::~AnimalFactory() {}
AnimalFactory& AnimalFactory::operator=(const AnimalFactory &other) { return *this;}

std::shared_ptr<AnimalFactory> AnimalFactory::animalFactory;
std::recursive_mutex AnimalFactory::mtx;

std::shared_ptr<AnimalFactory> AnimalFactory::getAnimalFactory()
{
    if(animalFactory == nullptr)
    {
        mtx.lock();

        if(animalFactory == nullptr)
            animalFactory = std::make_shared<AnimalFactory>();  //getting error
        mtx.unlock();                                           //in this line
    }
    return animalFactory;
}

std::unique_ptr<AnimalPrototype> AnimalFactory::getAnimal(const std::string &animalType)
{
    return myMap[animalType]->clone();
}


Thanks :)
Last edited on
As the compiler said, your call to std::make_shared requires a default-constructible type, and yours isn't: its constructor is private.

You can get around this by using a private key idiom:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class AnimalFactory
{
    private:
+       struct token{};
        AnimalFactory();
        AnimalFactory(const AnimalFactory &);
...
    public:
+       AnimalFactory(token) : AnimalFactory() {}
        virtual ~AnimalFactory();
        static std::shared_ptr<AnimalFactory> getAnimalFactory();
...
-           animalFactory = std::make_shared<AnimalFactory>();
+           animalFactory = std::make_shared<AnimalFactory>(token{});


Also, why so many layers of complexity? Singletons are the thing to avoid, not to make (and so are the recursive mutexes, by the way), but if you must make a singleton, the standard C++ solution is just a reference to a function-local static:

1
2
3
4
5
AnimalFactory& AnimalFactory::getAnimalFactory()
{
    static AnimalFactory instance;
    return instance;
}

In the code shown, though, there's no need for even that. You can have a factory function without any class.
Last edited on
Topic archived. No new replies allowed.