Exercise: Singleton (Flexible And Strict)¶
Complications¶
In Exercise: Singleton (Flexible), we showed a more flexible way to instantiate the instance at runtime.
Unfortunately, that implementation has the its own shortcomings:
Overwriting the instance can only result in a runtime error
Program startup has to be crafted carefully
Users are now explicitly enabled to instantiate either of the two implementation (alas, it’s the user who writes startup code)
All in all: users see that there are concrete implementations, and must be told rules:
Only instantiate concrete implementation at startup
After startup, only access interface via
SocialInsurance::instance()
Quick fix: re-instantiate the requirements from Exercise: Singleton (Inflexible):
Eliminate the offending
SocialInsurance::set_instance()
method.Introduce an environment variable
SOCINSUR
that is set to eithername()
of the available implementations (i.e.,SVS
orOEGK
).Modify
SocialInsurance::instance()
to read theSOCINSUR
environment variable, and to instantiate the respective inisurance implementation.
Reimplement the class hierarchy such that the following program can run. Take special care:
Uncomment the commented-out lines and make sure that they emit compiler errors.
There must not be a memory leak at program end.
#include "social-insurance-flexible-strict.h"
// only there to deny compiability below
// #include "social-insurance-svs-strict.h"
// #include "social-insurance-oegk-strict.h"
#include <iostream>
#include <string>
int main()
{
std::string id("1037190666");
SocialInsurance::instance().charge(id, 1254.60);
SocialInsurance::instance().charge(id, 231.34);
std::cout << id << " owes \"" << SocialInsurance::instance().name() << "\" " << SocialInsurance::instance().debt(id) << " Euros" << std::endl;
// MUST NOT COMPILE
// ================
// explicit instantiation (neither iface nor implementations)
// ----------------------------------------------------------
// SocialInsurance iface_instance("Another Insurance");
// SVS svs_instance;
// OEGK oegk_instance;
// copy initialization
// -------------------
// SocialInsurance another_instance = SocialInsurance::instance();
// copy assignment
// ---------------
// another_instance = SocialInsurance::instance();
// and dynamic_cast?
// -----------------
// STOP HERE!!!
return 0;
}
Tests¶
SOCINSUR=OEGK
$ SOCINSUR=OEGK ./singleton-social-insurance-flexible-strict-main 1037190666 owes "OEGK" 1485.94 Euros
SOCINSUR=SVS
$ SOCINSUR=SVS ./singleton-social-insurance-flexible-strict-main 1037190666 owes "SVS" 1634.53 Euros
SOCINSUR
unset$ ./singleton-social-insurance-flexible-strict-main terminate called after throwing an instance of 'std::runtime_error' what(): Environment variable "SOCINSUR" is not set Aborted (core dumped)
SOCINSUR
invalid$ SOCINSUR=xxx ./singleton-social-insurance-flexible-strict-main terminate called after throwing an instance of 'std::runtime_error' what(): Environment variable "SOCINSUR" has invalid value Aborted (core dumped)