I have a class foo. Operations on foo require a call to foo::open(), a number of foo::write(), and must end with a foo::close() call:
#include <iostream>
class foo
{
public:
foo()
{
std::cout << "foo::foo()" << std::endl;
}
~foo()
{
std::cout << "foo::~foo()" << std::endl;
}
void open()
{
std::cout << "foo::open()" << std::endl;
}
void close()
{
std::cout << "foo::close()" << std::endl;
}
void write(const std::string& s)
{
std::cout << "foo::write(" << s << ")" << std::endl;
}
private:
// state that must be retained for entire lifetime of object
};
static void useFoo(foo& my_foo)
{
my_foo.open();
my_foo.write("string1");
my_foo.write("string2");
my_foo.close();
}
int main( int argc, char* argv[] )
{
foo my_foo;
useFoo(my_foo);
useFoo(my_foo);
}
As expected, this outputs the following:
foo::foo()
foo::open()
foo::write(string1)
foo::write(string2)
foo::close()
foo::open()
foo::write(string1)
foo::write(string2)
foo::close()
foo::~foo()
I want to give users of my class foo a way of ensuring that they don't forget to call foo::close(), and to ensure that foo::close() gets called if an exception happens. I can't use foo's destructor as foo must continue to exist after a foo::close(), ready for the next foo::open().
I came up with this RAII implementation:
#include <iostream>
class foo
{
public:
class opener
{
public:
explicit opener(foo& my_foo):foo_(my_foo)
{
foo_.open();
};
~opener()
{
foo_.close();
};
private:
foo& foo_;
};
foo()
{
std::cout << "foo::foo()" << std::endl;
}
~foo()
{
std::cout << "foo::~foo()" << std::endl;
}
void open()
{
std::cout << "foo::open()" << std::endl;
}
void close()
{
std::cout << "foo::close()" << std::endl;
}
void write(const std::string& s)
{
std::cout << "foo::write(" << s << ")" << std::endl;
}
opener get_opener()
{
return(opener(*this));
}
private:
// state that must be retained for entire lifetime of object
};
static void useFoo(foo& my_foo)
{
foo::opener my_foo_opener = my_foo.get_opener();
my_foo.write("string1");
my_foo.write("string2");
}
int main( int argc, char* argv[] )
{
foo my_foo;
useFoo(my_foo);
useFoo(my_foo);
}
For simplicity I haven't included the obvious improvement of having the foo::opener class expose the foo::write() method, though in a real object I'd do this to prevent a write() being possible before an open().
EDIT As Nawaz points out below, a real class would also need a copy constructor and assignment operator.
This seems quite a lot of boilerplate just to ensure that a close() gets called. Two questions arise:
Is this still simpler than forcing the users of my class to use a try/catch?
Is there a simpler way to achieve what I want: provide the basic exception guarantee and ensure that close() always follows open()?
The nested class opener should implement the copy-semantics, as the default code generated by the compiler would produce undesirable result, if I correctly understood your intention.
So please implement copy-constructor, and copy-assignment.
Or alternatively, you may want to disable copy-semantic altogether, by making their declarations1 private, much like implementation of all standard stream classes. I would prefer this approach.
1. Note that you don't need to define them. Just declaring them in the private section is enough.
Can close ever fail? If it can, then you're going to need to take extra care regardless of approach. I think the RAII way is simpler than forcing exception handling/closing on your users though.
Is foo really so complex (or is it a global?) to create and destroy that you can't just have its destructor call close instead of using the opener to do the matching open/close?
Or if this is implementing some sort of transaction semantics I can't see a simpler way than the opener class (but as noted in other answers you probably want to disable copying and assignment of the opener class).
I think you should separate your concerns:
one class to store the state that is carried throughout
one class to handle the transient state within a open/close, which also takes care of all the "transient" operations like write
The "transient" class takes the "data" class as parameter (by reference) and will update it during the various method calls.
Then you can use typical RAII on the transient class and still have state propagated throughout.
This is a classic case for using RAII. Do use the constructor and destructor: if you want to open() again, instantiate a new foo. The idea of RAII is that an instantiation represents a single resource use. That's how you get the guarantee for resource cleanup.
struct foo {
foo() { open(); }
~foo() { close(); }
void write(const std::string& s);
private: // or public
foo(const foo&);
foo& operator=(const foo&);
};
// ...
{ foo fooa;
fooa.write("hello 0");
} { foo foob;
foob.write("hello 1");
}
You could add a flag to the class, that is set to true if you called open() and to false if you called close(). If open() is called you can check if the flag is true or false and and close if you need to do so before proceeding.
Related
Assume I have a templated MemoryPool class a function create(...) (which returns a pointer to a newly allocated object of type T) and a function destroy(T*) (which destroys and returns the memory back to the pool).
I would like to create a std::unique_ptr that "owns" the pointer created by the pool and returns the pointer to the pool, thus requiring a custom deleter.
The problem is, how do I make this work if the pool contains concrete objects and I want to pass around a std::unique_ptr to an abstract interface of this object.
Here is an example that doesn't compile:
#include <iostream>
#include <memory>
#include <functional>
#include <utility>
template <typename T>
class MemoryPool {
public:
template <typename ... ARGS>
T* create(ARGS&&... args) {
std::cout << "MemoryPool::create()" << std::endl;
return new T(std::forward<ARGS>(args)...);
}
void destroy(T* ptr) {
std::cout << "MemoryPool::destroy()" << std::endl;
delete ptr;
}
};
class ITest {
public:
ITest() {
std::cout << "ITest::ITest()" << std::endl;
}
virtual ~ITest() {
std::cout << "ITest::~ITest()" << std::endl;
}
virtual void sayHello() = 0;
};
class Test :public ITest {
public:
Test() {
std::cout << "Test::Test()" << std::endl;
}
~Test() {
std::cout << "Test::~Test()" << std::endl;
}
void sayHello() override {
std::cout << "Test says hello" << std::endl;
}
};
class ITestOwner {
public:
ITestOwner(std::unique_ptr<ITest> ptr) :
_ptr(std::move(ptr))
{
std::cout << "ITestOwner::ITestOwner()" << std::endl;
}
~ITestOwner() {
std::cout << "ITestOwner::~ITestOwner()" << std::endl;
}
void sayHello() { _ptr->sayHello(); }
private:
std::unique_ptr<ITest> _ptr;
};
int main() {
MemoryPool<Test> pool;
std::unique_ptr<Test, std::function<void(Test*)>> ptr(pool.create(), [&pool](Test* ptr){
std::cout << "Custom Deleter" << std::endl;
pool.destroy(ptr);
});
ITestOwner owner(std::move(ptr));
owner.sayHello();
return 0;
}
Keep in mind that, my real MemoryPool class would actually act as a normal memory pool and not use new/delete as I have done.
In this example, ITestOwner should take over ownership of the std::unique_ptr to a ITest abstract object. Then, when ITestOwner is destroyed, the smart pointer will be destroyed, and the Test object should be returned to the memory pool.
Is there a way to accomplish this?
The code doesn't compile because std::unique_ptr<ITest> is used by ITestOwner while you to forward it std::unique_ptr<Test, std::function<void(Test*)>>. It obviously doesn't compile because std::unique_ptr<ITest> calls delete on ITest instead of calling some complex arbitrary function.
You'd need to use unique_ptr<ITest, function<void(ITest*)>> for it to work and in addition add some unsighty conversion code from function<void(Test*)> to function<void(ITest*)>... I'd say this is simply not good. unique_ptr is designed to be simple and efficient - the destructor is supposed to wrap basic functionality but it isn't convenient enough for complicated purposes.
Basically, unique_ptr is not designed for this task. It is supposed to be lightweight and you already use heavy functionality like std::function that ruins the whole purpose. Instead, you can use shared_ptr which type erases the deleter and hides it - so you'd need nothing to worry about. If you want to still restrict user to unique ownership you can surely find other 3rd party open source libraries that implement the smart pointer you want - there are lots of them.
I got a class which holds the application's logger as a unique_ptr. The logger can be set through a static function. Also, one can obviously log messages. I left out any thread synchronization (mutexes) to make things easier.
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<logger::ILogger> new_logger);
static void Log(const std::string& message);
private:
static std::unique_ptr<logger::ILogger> logger_;
};
void LoggerWrapper::Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
}
void LoggerWrapper::SetLogger(std::unique_ptr<logger::ILogger> new_logger) {
logger_ = std::move(new_logger);
}
My problem is: The unique_ptr gets destructed before some of the other classes inside the application. E.g. is the DTOR of Class Foo wants to log something, the unique_ptr might have already been destroyed (which is the case at the moment). This causes the ILogger implementation to be destroyed, resulting in no log output being possible.
Does anyone have an idea on how to easily fix this? I somehow need to "delay" the destruction of the static unique_ptr. I also tried changing it to a shared_ptr, but that only caused SIGABRTs with "pure virtual method called" errors.
Thanks in advance!
EDIT: Created a minimal working example which contradicts my experience. In this case, the static logger outlives the Foo class.
EDIT2: My application uses exit. That seems to change the order of destruction.
EDIT3: exit does not destroy local objects.
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
logger_ = std::move(new_logger);
}
static void Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
private:
static std::unique_ptr<ILogger> logger_;
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
// declaring logger_ first causes it to be deleted AFTER foo
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
foo = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
This is trivial.
First you don't use global static objects ( you should not be using global state like that). You use function static objects so you can control the order of creation/destruction.
So change this:
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
Into:
class GlobalLogger
{
public:
ILogger& getLogger() {
static ILogger logger; // if you must use unique_ptr you can do that here
return logger; // But much simpler to use a normal object.
}
};
class GlobalFoo
{
public:
Foo& getFoo() {
// If there is a chance that foo is going to
// use global logger in its destructor
// then it should simply call `GlobalLogger::getLogger()`
// in the constructor of Foo. You then
// guarantee the order of creation and thus destruction.
// Alternatively, you can call it here in thus
// function just before the declaration of foo.
static Foo foo;
return foo;
}
};
// Where you were using `logger_` use `GlobalLogger::getLogger()`
// Where you were using `foo` use `GlobalFoo::getFoo()`
If we use your original code as the starting point we can do this:
#include <iostream>
#include <memory>
#include <string>
// Please don't do this.
// This is the number one worst practice.
// https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper
{
// Here store the logger
// as a static member of this private function.
// The the SetLogger() Log() functions get this reference.
static std::unique_ptr<ILogger>& getLogReference() {
static std::unique_ptr<ILogger> logger;
return logger;
}
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
// Save the new reference.
getLogReference() = std::move(new_logger);
}
// Use the logger if it has been set.
static void Log(const std::string& message) {
std::unique_ptr<ILogger>& logger_ = getLogReference();
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
// This calls Log()
// Which calls getLogReference()
// Which forces the creation of the function static
// variable logger so it is created before this
// object is fully initialized (if it has not already
// been created).
//
// This means this object was created after the logger
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
// Because the Log() function was called in the
// constructor we know the loger was fully constructed first
// thus this object will be destroyed first
// so the logger object is guaranteed to be
// available in this objects destructor
// so it is safe to use.
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
std::unique_ptr<Foo>& globalFoo() {
// foo may destroy an object created later
// that has a destructor that calls LoggerWrapper::Log()
// So we need to call the Log function here before foo
// is created.
LoggerWrapper::Log("Initializing Global foo");
// Note: Unless somebody else has explicitly called SetLogger()
// the above line is unlikely to log anything as the logger
// will be null at this point.
static std::unique_ptr<Foo> foo;
return foo;
}
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
globalFoo() = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}
The order in which static (global) objects are created and destroyed is undefined. This leave you a few options.
Don't use global objects, just raw use pointers which you can destroy yourself in the correct order.
Use a pointer to your logger that you never destroy. This technically is a memory leak but the kernel will cleanup when your application exits.
Use a shared_ptr for your logger. Each object that uses the logger gets a shared_ptr and the logger will be cleaned up after the last object is destroyed.
Inversion of control is a value-proof technique which is used to modularize a system and decouple the components from each other.
Low coupling is always an advantage: it simplifies automatic testing of the components and makes the code better conforming to single responsibility principle.
Among the ways to declare a dependency to another class (service locator, property injection calling a public method / setting a public property...), the constructor injection seems the best approach.
Though it's probably the most difficult one (at least from the listed three) to implement, it comes with significant advantages:
all the dependencies are truly visible with constructor signature;
cyclic dependencies don't happen because of the well-defined order of instantiation.
What are the pros / cons of the many choices C++ offers to perform the injection via constructor?
Instance copyable class
class object
{
public:
object(dependency d) : dep_(d) {}
private:
dependency dep_;
};
Only works in case dependency class is completely stateless, i.e. doesn't have any members. Practically, this rarely happens because dependency class may store its own dependency.
Raw pointer
class object
{
public:
object(dependency *d) : dep_(d)
{
if (d == nullptr)
throw std::exception("null dependency");
}
private:
dependency *dep_;
};
This works like true injection. We're required to check the passed pointer for nullptr value.
object class does not own dependency class, thus it's the responsibility of calling code to make sure the object is destroyed before the dependency object.
In real application, it's sometimes very difficult to validate.
Reference
#define DISALLOW_COPY_AND_ASSIGN(Class) \
Class(const Class &) = delete; \
Class &operator=(const Class &) = delete
class object
{
public:
object(dependency &d) : dep_(d) {}
DISALLOW_COPY_AND_ASSIGN(object);
private:
dependency &dep_;
};
The reference cannot be null, so it's a bit safer in this prospective.
However this approach brings additional constraints to object class: it has to be non-copyable since a reference cannot be copied. You have to either manually override assignment operator and copy constructor to stop from copying or inherit it from something like boost::noncopyable.
Like with raw pointer, the ownership constraint is in place. Calling code should provide the correct destruction order for both classes, otherwise the reference becomes invalid and application crashes with access violation.
If the dependency is a const reference:
class object
{
public:
object(const dependency &d) : dep_(d) {}
private:
const dependency &dep_;
};
you should pay attention to the fact that the object class accepts references to temporary objects:
dependency d;
object o1(d); // this is ok, but...
object o2(dependency()); // ... this is BAD.
Further details:
C++: non-temporary const reference
What are the advantages of boost::noncopyable for several approaches to prevent copying a class
Should I prefer pointers or references in member data?
Using reference as class members for dependencies
Smart pointer
class object
{
public:
object(std::shared_ptr<dependency> d) : dep_(d)
{
if (!d)
throw std::exception("null dependency");
}
private:
std::shared_ptr<dependency> dep_;
};
Similar to raw pointer but the ownership is controlled by smart pointer mechanism.
Still need to check for nullptr in the constructor body.
The major advantage is the dependency object lifetime control: there is no need for the calling application to properly control the destruction order (but consider that you need to be very careful when designing your APIs with std::shared_ptr).
Once the dependency class is no longer used it's automatically destroyed by shared_ptr destructor.
There are cases when shared_ptr owned objects are not destroyed (so called cyclic references). However, with constructor injection, cyclic dependencies aren't possible due to the specific well-defined order of construction.
This works of course if no other injection methods are used across the application.
A smart pointer has a small overhead but it isn't a real problem in the majority of cases.
Further details:
Disadvantages of shared_ptr
GotW #91: Smart Pointer Parameters
This is an old question but for me this is a hot topic because I've found automatic dependency injection sorceries in all web the framewrks I could hear of, they are often built with introspection shananigans and I always have great time discovering their implementations. But I couldn't find an easy way to do the same in C++.
The service locator approach can solve the problem pretty well indeed but declaring the dependencies in the constructor and getting rid of such pattern in between seems cleaner and more flexible to use because it is easier to instantiate your classes passing different instances of your services.
But the service locator approach can also handle cyclic dependencies because they can be lazily picked, and sometimes cyclic dependencies can happen (maybe in bad code only).
Unfortunately I haven't figured out way to detect the types of the arguments in constructors and automatically inject instances of such types, yet.
Anyway I want to share the best solution I found so far to automatically inject deendencies in classes. It is similar to a service locator that handles its service as a singleton with smart pointers and can be used for dependency injection, but it have to be revised to allow two classes that have some dependencies in common to get different instances of the same type.
template<typename T>
struct di_explicit
{
static std::shared_ptr<T> ptr;
virtual ~di_explicit()
{
if(di_explicit<T>::ptr.use_count() == 1) {
reset();
}
}
virtual std::shared_ptr<T> get()
{
return di_explicit<T>::ptr;
}
static void reset()
{
di_explicit<T>::ptr.reset();
}
static void swap(std::shared_ptr<T> arg)
{
arg.swap(di_explicit<T>::ptr);
}
static void emplace(auto && ... args)
{
swap(std::make_shared<T>(std::forward(args) ...));
}
static void emplace_if_not_exists(auto && ... args)
{
if(!di_explicit<T>::ptr) {
emplace(std::forward(args) ...);
}
}
};
template<typename T>
std::shared_ptr<T> di_explicit<T>::ptr {};
template<typename T>
struct di : di_explicit<T>
{
di(auto && ... args)
{
di_explicit<T>::emplace_if_not_exists(std::forward(args) ...);
}
};
template<typename T>
struct di_lazy : di_explicit<T>
{
auto get(auto && ... args)
{
di_explicit<T>::emplace_if_not_exists(std::forward(args) ...);
return di_explicit<T>::ptr;
}
};
The ideas behind the above snippet are:
It is a logic wrapper that handles the memory of another class, such wrapper is able to automatically create an instance of the managed class and pass the reference as a singleton when requested, the memory is automatically deallocated when there are no more reference to the managed object.
It is possible to use a specific instance of the managed class (or a subtype) so that the user can declare a dependency to an interface of the needed service and instanciate the concrete dependency when the program is running or a mock during tests.
In case of circular dependency there is a way to lazily instanciate the needed dependency.
The basic logic is coded in the base class di_explicit<T> that uses a static shared_ptr<T> to make the singletons, and a destructor that resets the shared pointer when the last reference left is the static one (stored in di_explicit<T>).
The struct di : di_explicit<T> retrive the dependency in its constructor while di_lazy : di_explicit<T> only does it when the dependency is requested (in the get() method).
The following is an example (non lazy) with a mock.
namespace {
struct dependency {
virtual void do_something() {
std::cout << "doing something" << std::endl;
}
};
struct mock : dependency {
using dependency::do_something;
void do_something() {
std::cout << "mocking something" << std::endl;
}
};
struct srv {
di<dependency> dep;
void do_stuff() {
std::cout << "doing stuff" << std::endl;
return dep.get()->do_something();
}
};
int test = [](){
// the classes are not instanciated yet
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
{
// the classes instanciated here
di<srv> s;
s.get()->do_stuff();
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
} // <- the instances are destroyed here
std::cout << "ptr exists " << !!di<srv>::ptr << std::endl;
{
// use a mock instance
di_explicit<dependency>::swap(std::make_shared<mock>());
di<srv>{}.get()->do_stuff();
} // <- the mock is destroyed here too
std::cout << "ptr exists " << !!(di<dependency>::ptr) << std::endl;
return 0;
}();
}
The following is an example with circular references and di_lazy.
namespace {
struct dep_2;
struct dep_3;
struct dep_1 {
di_lazy<dep_2> dep;
void do_something();
};
struct dep_2 {
di_lazy<dep_3> dep;
void do_something();
};
struct dep_3 {
di_lazy<dep_1> dep;
void do_something() {
std::cout << "dep_3 do_something" << std::endl;
dep.get()->do_something();
}
virtual void do_something_else() {
std::cout << "dep_3 do_something_else" << std::endl;
}
};
void dep_1::do_something() {
std::cout << "dep_1 do_something" << std::endl;
dep.get()->do_something();
}
void dep_2::do_something() {
std::cout << "dep_2 do_something" << std::endl;
dep.get()->do_something_else();
}
struct srv_2 {
di<dep_3> dep;
void do_something() {
std::cout << "srv_2 do_something" << std::endl;
return dep.get()->do_something();
}
};
int result = [](){
{
// neither the dependencies or the service are requested yet
di_lazy<srv_2> wrapper{};
// here the service is requested
auto s = wrapper.get();
// dependencies are requested inside this function
s->do_something();
}
{
struct mock_dep_3 : dep_3 {
virtual void do_something_else() {
std::cout << "dep_3 do_something_else MOCKED!" << std::endl;
}
};
// a mock can be used with di_lazy as well
di_explicit<dep_3>::swap(std::make_shared<mock_dep_3>());
di<srv_2>{}.get()->do_something();
}
return 0;
}();
}
I know there is room for improvements (any sugestion are appreciated), I hope you find it useful
EDIT
I found a sligly better way to do the same but this time extending the std::shared_ptr class itself.
It is still some kind of service locator but with the following snippet is also possible to pass shared pointers as arguments in your constructors
template<typename T>
class di : public std::shared_ptr<T>
{
static std::shared_ptr<T> ptr;
public:
static void reset()
{
di<T>::ptr.reset();
}
static di<T> replace(std::shared_ptr<T> ptr)
{
di<T>::ptr = ptr;
return di<T>::ptr;
}
template<typename ... args_t>
static di<T> emplace(args_t && ... args)
{
return di<T>::replace(std::make_shared<T>(
std::forward<args_t>(args) ...
));
}
static di<T> instance()
{
return di<T>::ptr;
}
~di()
{
if(this->is_linked() && di<T>::ptr.use_count() <= 2){
di<T>::ptr.reset();
}
}
bool is_linked()
{
return *this && di<T>::ptr.get() == this->get();
}
template<typename ... args_t>
di(args_t && ... ptr) : std::shared_ptr<T>(std::forward<args_t>(ptr) ...)
{}
};
template<typename T>
std::shared_ptr<T> di<T>::ptr {};
With this class you can pass the instance of some service to another using constructor
ie
struct logger_interface
{
virtual void log(std::string) = 0;
virtual ~logger_interface() = default;
};
struct some_service_interface
{
virtual void serve() = 0;
virtual ~some_service_interface() = default;
};
struct logger_with_id : logger_interface
{
static int counter;
int id = ++counter;
void log(std::string s) {
std::cout << id << ") " << s << std::endl;
}
};
int logger_with_id::counter = 0;
struct some_service : some_service_interface
{
di<logger_interface> logger;
some_service(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void serve() {
logger->log("serving...");
}
};
int app = []() {
di<logger_interface>::replace(di<logger_with_id>::emplace());
di<some_service_interface>::replace(di<some_service>::emplace());
std::cout << "running app"<< std::endl;
di<logger_interface>::instance()->log("app");
di<some_service_interface>::instance()->serve();
std::cout << std::endl;
return 0;
}();
Will print
running app
1) app
1) serving...
And if you need you can override the dependency for some service
struct decorated_logger : logger_interface {
di<logger_interface> logger;
decorated_logger(
di<logger_interface> logger = di<logger_interface>::instance()
) :
logger(logger)
{}
void log(std::string s) {
logger->log("decorating...");
logger->log(s);
}
};
int app_with_custom_logger_on_service = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running app_with_custom_logger_on_service"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return 0;
}(
di<logger_interface>::replace(std::make_shared<logger_with_id>()),
di<some_service_interface>::replace(std::make_shared<some_service>(
std::make_shared<decorated_logger>(std::make_shared<logger_with_id>())
))
);
Will print
running app_with_custom_logger_on_service
2) app
3) decorating...
3) serving...
This can also be used for tests
struct mock_logger : logger_interface {
void log(std::string) {
std::cout << "mock_logger" << std::endl;
}
};
struct mock_some_service : some_service_interface {
void serve() {
std::cout << "mock_some_service" << std::endl;
}
};
int test = [](
di<logger_interface> logger,
di<some_service_interface> service
) {
std::cout << "running test"<< std::endl;
logger->log("app");
service->serve();
std::cout << std::endl;
return 0;
}(
di<logger_interface>::replace(std::make_shared<mock_logger>()),
di<some_service_interface>::replace(std::make_shared<mock_some_service>())
);
Will print
running test
mock_logger
mock_some_service
I made a gist for this example, you can run it on wandbox with clang
I'm a bit rusty on my C++ and have run into a bit of a snag.
I have a class, in the example user which takes a reference to an abstract class for its constructor. Ideally, I'd like for the class to support the following syntax:
User u( Sub("") );
u.work();
I have an abstract class super with a base class called sub. The user class takes a reference to super in its constructor. At runtime, user is passed a temporary reference to sub.
When u.work() is called I get an exception - because the temporary has been deconstructed. (Oddly enough I get a different behaviour if I remove the destructors on super and sub).
Example code is below!
Is there a way to fix this problem?
I know there are lots of ways if I accept to change the signature and change the syntax at the call site, but I'd prefer to hold on to the calling signature:
User u( Sub("") );
u.work();
Example code
class Super {
public:
Super()
{
std::cout << __FUNCTION__ << std::endl;
};
virtual ~Super()
{
std::cout << __FUNCTION__ << std::endl;
}
virtual void func() = 0;
};
class Sub : public Super
{
public:
Sub(char* name) :
name_(name)
{
std::cout << __FUNCTION__ << std::endl;
};
virtual ~Sub()
{
std::cout << __FUNCTION__ << std::endl;
}
virtual void func()
{
std::cout << __FUNCTION__ << std::endl;
}
char* name_;
};
class User
{
public:
User(Super& s) :
super_(s)
{
std::cout << __FUNCTION__ << std::endl;
}
~User()
{
std::cout << __FUNCTION__ << std::endl;
}
void work()
{
std::cout << __FUNCTION__ << std::endl;
super_.func();
}
Super& super_;
};
int main()
{
User u( Sub("") );
u.work();
return 0;
}
The lifetime of a temporary object like your Sub("") ends at the end of the full-expression in which it appears, i.e. at the semicolon.
C++ doesn't allow you to bind such temporary objects to mutable references, but Microsoft's compiler does allow that. Nonetheless, initializing a class member reference from such a temporary value immediately produces a dangling reference, which you must never ever use again; evaluating it outside the constructor body results in undefined behaviour.
The way to fix this is to not store references in your class!
For example, if you wanted ownership of a polymorphic value, you could use a unique pointer:
#include <memory>
class User
{
std::unique_ptr<Super> s_;
public:
User(std::unique_ptr<Super> s) : s_(std::move(s)) {}
void work() { s_->func(); }
};
User u(std::make_unique<Sub>("Hello"));
u.work();
The difference you are seeing between various attempts are all just accidents within undefined behavior. The structure of Super and Sub is just a distraction.
You can't keep a reference to a temporary.
User(Super& s) :
super_(s)
...
Super& super_;
The reference passed in to initialize super_ must be to an object that lasts at least as long as super_ can be used.
I know there are lots of ways if I accept to change the signature and
change the syntax at the call site, but I'd prefer to hold on to the
calling signature:
You are pretty far from any valid design. But if you really want to pass, then keep, a polymorphic temp object that way, you could put a virtual clone method into Super to support something like:
User(Super& s) :
super_(s.clone())
...
std::unique_ptr<Super> super_;
Your problem is the ownership of the Sub(). Currently you create it, take the reference of it, and just after that it gets destructed.
A proper way may be to pass a pointer to Sub to User, and let User take ownership, keeping the Sub until it no longer needs the Sub. This may look like:
class User
{
Super *super_;
public:
User(Super *super)
: super_(super)
{
}
~User()
{
delete super_;
}
};
User u( new Sub("") );
Suppose I have an RAII-style C++ class:
class StateSaver
{
public:
StateSaver(int i) { saveState(); }
~StateSaver() { restoreState(); }
};
...to be used like so in my code:
void Manipulate()
{
StateSaver save(1);
// ...do stuff that modifies state
}
...the goal being to enter some state, do stuff, then leave that state when I leave that scope. Is there a way to make this typo not compile (or warn, or somehow complain so that the mistake can be noticed)?
void Manipulate()
{
StateSaver(1); // ruh-roh, state saved and immediately restored!
// ...do stuff that modifies state
}
I'm not aware of anything in C++ itself which I could use to prevent this, but that doesn't mean it doesn't exist. If there isn't anything in C++, compiler-specific extensions would be acceptable. I'm primarily interested in anything targeting gcc and msvc (someday icc, ideas for other compilers welcome but less likely to be useful) so hacks for any of them would be useful (abstracted into appropriately #ifdef'd macro definitions, of course).
I'm not sure if anything can be done at compile-time. For a run-time check, you could do this:
struct SaveMatrix
{
SaveMatrix(const SaveMatrix& that) {
assert(this == &that);
glPushMatrix();
}
~SaveMatrix() { glPopMatrix(); }
};
Which requires the client to write:
SaveMatrix sm(sm);
and there's no way to do the same for a temporary without binding it to an identifier (at which point it's no different from an auto variable).
SaveMatrix save(); doesn't define an object either. It declares a function.
There's very little you can do to prevent others (or yourself, FTM) from doing something else than they wanted to. The only thing I can think of is not writing the code itself, but writing a macro instead.
#define SAVE_MATRIX SaveMatrix save ## __LINE__
However, this is quite ugly. OTOH, it does catch the error at compile-time.
I actually had to tweak my solution in a bunch of ways from the variant Waldo posted, but what I eventually got to is a macro-ized version of:
class GuardNotifier
{
bool* notified;
public:
GuardNotifier() : notified(NULL) { }
void init(bool* ptr) { notified = ptr; }
~GuardNotifier() { *notified = true; }
};
class GuardNotifyReceiver
{
bool notified;
public:
GuardNotifyReceiver() : notified(false) { }
void init(const GuardNotifier& notifier)
{ const_cast<GuardNotifier&>(notifier).init(¬ified); }
~GuardNotifyReceiver() { assert(notified); }
};
class StateSaver
{
GuardNotifyReceiver receiver;
public:
StateSaver(int i,
const GuardNotifier& notifier = GuardNotifier())
{
receiver.init(notifier)
saveState();
}
~StateSaver()
{
restoreState();
}
};
The class can never tell if it was instantiated as a temporary (SaveMatrix()) or as a variable (SaveMatrix save;). I think the best way to stop the programmer doing that without stack or macro hacks is to force a member function call after construction, eg:
class RAII
{
public:
bool valid;
RAII()
: valid(false)
{
cout << "RAII ctor" << endl;
}
void Do()
{
valid = true;
}
~RAII()
{
assert(valid);
cout << "RAII dtor" << endl;
}
};
This then works as follows:
{
// Intended use
RAII raii;
raii.Do();
cout << "Some task" << endl;
}
{
// Woops: forgot Do()
RAII raii;
cout << "Some task" << endl;
}
{
// Woops: forgot Do()
RAII();
cout << "Some task" << endl;
}
{
// Programmer shot self in foot, hopefully the act of typing this would make them realise that
RAII().Do();
cout << "Some task" << endl;
}