user3692418
user3692418

Reputation: 335

C++: Singleton? How to pass arguments to the construtors?

I am reading Item 47 in "Effective C++". In the book it is suggested that the so called non-local static objects should be used with special care. Instead it suggests to use something like below:

Directory& tempDir()  
{  
         static Directory td;  
         return td;  
} 

I am not so sure if it should be called as singleton. However, I am thinking how I can pass arguments to the constructor of class Directory. For instance, I want to pass a path as a string to Directory td, perhaps I need to do it like this:

Directory& tempDir(std::string & str)  
{  
         static Directory td(str);  
         return td;  
} 

The problem is that whenever I want to access Directory td, I have to pass the string as the input argument. This is not so beautiful.

Does anyone have more elegant way of doing this?

Thank you.

Upvotes: 2

Views: 1695

Answers (3)

R Sahu
R Sahu

Reputation: 206707

My suggestion.

Keep the first version of tempDir.

Directory& tempDir()  
{  
   static Directory td;  
   return td;  
} 

Add a member function to Directory to set the path. When you need to set the path, use:

tempDir().setPath(path);

Using this approach allows creation of singletons that have state. You can get and set other state associated with the singleton using similar accessor and modifier functions.

Upvotes: 0

Keith
Keith

Reputation: 6834

I presume that you wish to initialize the global instance, but then access it as a singleton.

You can do it like this:

class Directory
{ 
public: 
    Directory& tempDir(const std::string & str)
    {
        if (tempDir_ == nullptr)
        {
            tempDir_ = new Directory(str);
        }
        return *tempDir_;
    }
    Directory& tempDir()
    {
        assert(tempDir_);
        // Or throw an execption etc.
        return *tempDir_;
    }

private:
    Directory(const std::string & str)
    {
        // etc.
    }
    static Directory* tempDir_;
};

Obviously, you need to make sure that initialization call does happen first, or restructure the approach.

Also, you might prefer to change tempDir(const std::string & str) to initialiseTempDir(const std::string & str) or some such.

Upvotes: 0

Columbo
Columbo

Reputation: 60999

Does anyone have more elegant way of doing this?

Instead of passing the path in the function, write a global function which "generates" the path:

char const* get_path()
{
    // do_stuff and return the path
}

Directory& tempDir()  
{  
         static Directory td(get_path());  
         return td;  
} 

The better way would be not to use a singleton though. Create the object in the main()-function, initialize it there and pass it by reference for all components.

You can of course have default parameter values like Directory& tempDir(const std::string & str = "") , if this is of any help for your use case.

That's nonsense. Creating a temporary every time you call this function is completely unnecessary overhead.

Upvotes: 3

Related Questions