Reputation: 43
I need several unique objects which are always available as program runs. I followed the Singleton design pattern and it suggests using method getInstance()
to fetch the objects. But I prefer to retrieve the objects immediately without calling method. So I wrote a class which provides several unique objects returned by reference type instead of pointer.
class Priority
{
public:
static Priority &High;
static Priority &Medium;
static Priority &Low;
std::string getName(void);
int getLevel(void);
private:
Priority(int level, std::string const& name);
~Priority();
Priority(Priority const&);
const Priority &operator = (Priority const&);
int level_;
std::string name_;
};
Priority &Priority::High = Priority(3, "High");
Priority &Priority::Medium = Priority(2, "Medium");
Priority &Priority::Low = Priority(1, "Low");
Priority::Priority(int level, std::string const& name)
: level_(level), name_(name)
{ }
Priority::~Priority() { }
inline std::string Priority::getName(void)
{
return name_;
}
inline int Priority::getLevel(void)
{
return level_;
}
I wrote an example program that uses the above class.
int main()
{
Priority &m = Priority::High;
std::string name = m.getName();
int level = m.getLevel();
return 0;
}
The program worked fine. Hence I assumed the memory allocated for variable
Priority &Priority::High = Priority(3, "High");
won't be wiped out until the program stops or dll file storing the class is unloaded. Am I correct?
Upvotes: 2
Views: 1305
Reputation: 145204
The code you've shown shouldn't compile: you can't bind a reference to non-const
to an rvalue.
Examples with Visual C++ 11.0 and g++ 4.7.1:
[D:\dev\test] > cl foo.cpp foo.cpp foo.cpp(27) : warning C4239: nonstandard extension used : 'initializing' : conversion from 'Priority' to 'Priority &' A non-const reference may only be bound to an lvalue foo.cpp(28) : warning C4239: nonstandard extension used : 'initializing' : conversion from 'Priority' to 'Priority &' A non-const reference may only be bound to an lvalue foo.cpp(29) : warning C4239: nonstandard extension used : 'initializing' : conversion from 'Priority' to 'Priority &' A non-const reference may only be bound to an lvalue [D:\dev\test] > gnuc foo.cpp foo.cpp:27:48: error: invalid initialization of non-const reference of type 'Priority&' from an rvalue of type 'Priority' foo.cpp:28:50: error: invalid initialization of non-const reference of type 'Priority&' from an rvalue of type 'Priority' foo.cpp:29:47: error: invalid initialization of non-const reference of type 'Priority&' from an rvalue of type 'Priority' [D:\dev\test] > _
With Visual C++, use option /W4
(warning level 4) to get the warnings shown above.
You can put this and other “make it standard-conforming” options in the environment variable CL
(and ditto, LINK
for the Microsoft linker, e.g. /entry:mainCRTStartup
as a default linker option).
[D:\dev\test] > echo %CL% /nologo /EHsc /GR /W4 /FI"progrock/cppx/macro/c++11.for_msvc_11.h" [D:\dev\test] > _
Instead of lvalue references you could use rvalue references, but although Visual C++ is happy with that, g++ then complains about the private destructor.
So intead of the reference idea – what purpose was it meant to serve? – you can simply use ordinary static data members.
However, with ordinary static data members, as opposed to e.g. Meyers' singletons, you run the risk of banging into the static initialization order fiasco. So if you absolutely must provide globals, I recommend using singletons for that. And as for the kind of singleton, using the simplest possible solution is often the best, which means Meyers' singletons (I just linked the first reasonably-looking google result).
Upvotes: 1
Reputation: 171097
This shouldn't even compile, you're initialising the references with temporary objects. However, you don't need references there at all; just declare the static members as the objects directly:
In header:
class Priority
{
public:
static Priority High;
static Priority Medium;
static Priority Low;
//...
};
In source file:
Priority Priority::High(3, "High");
Priority Priority::Medium(2, "Medium");
Priority Priority::Low(1, "Low");
Upvotes: 1