user2889419
user2889419

Reputation:

C++ singleton pattern

Considering the following design for singleton pattern from yolinux (http://www.yolinux.com/TUTORIALS/C++Singleton.html)

#include <string>

class Logger{
public:
   static Logger* Instance();
   bool openLogFile(std::string logFile);
   void writeToLogFile();
   bool closeLogFile();

private:
   Logger(){};  // Private so that it can  not be called
   Logger(Logger const&){};             // copy constructor is private
   Logger& operator=(Logger const&){};  // assignment operator is private
   static Logger* m_pInstance;
};

would someone explain why Logger(Logger const&){}; and Logger& operator=(Logger const&){}; are required here?
Thanks in advance.

Upvotes: 1

Views: 1066

Answers (6)

Gabriel
Gabriel

Reputation: 3604

If you force the copy constructor and the assignment operators to be private then you won't be able to compile assignment of two Logger objects.

This will result in a linker error, which is not an explicit message. These methods are generated by default so you have to force them to be private

In C++11 they use the deleted methods to have a clearer message

   Logger(Logger const&)=delete;             // copy constructor does not exist
   Logger& operator=(Logger const&)=delete;  // assignment operator does not exist

The delete is not compulsory and the singleton works well without this feature so if you don't have this supported in your compiler you can just make it private it will work. This feature gives explicit errror messages but does not affect the behaviour of the singleton itself.

For more info about delete feature you can have a look here:

Meaning of = delete after function declaration

You can also prevent the object from being destroyed by making the destructor private.

What is the use of having destructor as private?

Upvotes: 3

DNamto
DNamto

Reputation: 1362

The traditional solution to achieve singleton behavior is to declare constructor private. The copy constructor and assignment operator (which intentionally have no implementations) are declared private to prevent any sort of copies being made

•Because they are private, this will lead to a compile-time error from anyone trying to use them that has not access to the private parts of the class.

•Which leaves friends (and the class itself) for which the error will occur under the form of undefined symbol, either at link-time (if you check for those there) or most probably at run-time (when trying to load the library).

Upvotes: 1

Honza Brabec
Honza Brabec

Reputation: 37608

Those are copy constructor and copy assignment operator. If they weren't defined as private they would be automatically generated as public and the instance would be copyable which contradicts the Singleton pattern.

Since the C++11 standard you could also use:

Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;

this syntax is perhaps clearer and also ensures that the object can't be copied even by friends and private members.

Upvotes: 1

Manu343726
Manu343726

Reputation: 14184

The copy constructor and the lvalue assigment operator are declared as private to make the type non-copyable.

On the other hand I encourage you to use the Meyers singleton instead of the dynamic-memory based: Its far easier to implement, not leaks (Note being strict that your singleton leaks memory, the instance is never deleted), and is thread-safe as defined in the C++11 standard memory model:

T& instance()
{
    static T _instance;

    return _instance;
}

Upvotes: 1

Matt
Matt

Reputation: 7160

The comments explain this quite nicely.

If you didn't explicitly define the constructor and copy constructor, then they will be created by default as public. By defining them here, you are making sure they are private, and so can never be called by the user.

Upvotes: 1

Max Frai
Max Frai

Reputation: 64356

From your link:

This design pattern and methodology ensures that only one instance of the C++ class is instantiated.

Logger(Logger const&) is a copy constructor which allows to copy object. And this is wrong by idea. Logger& operator=(Logger&) also allows to copy object.

Upvotes: 1

Related Questions