Best practices for dependency injection via constructor - c++

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

Related

How to use gmock SaveArgPointee with with std::shared_ptr of derived class

I have a BaseMessage class from which I derive several different DerivedMessage subclasses and want to send them like this:
class BaseMessage {
public:
virtual std::vector<uint8_t> data() const noexcept = 0;
virtual ~BaseMessage() = default;
[...]
}
class DerivedMessage : public BaseMessage {
public:
[...]
std::vector<uint8_t> data() const noexcept override { return m_data; }
private:
std::vector<uint8_t> m_data;
}
// simplified
class Tcp {
public
virtual void sendMessage(std::shared_ptr<BaseMessage> msg) { write(msg->data());}
[...]
};
class SomeClass {
public:
SomeClass(Tcp& tcp) : m_tcp(tcp) {}
void writeDataToRemote(std::shared_ptr<DerivedMessage> derived) const {
m_tcp.sendMessage(derived);
private:
Tcp m_tcp;
}
};
Now I want to write tests for SomeClass with gtest.
Therefore I mock the function of the TCP class:
class MockTcp : public Tcp {
MOCK_METHOD(void, sendMessage, (std::shared_ptr<ralco::CommandMsg> msg), (override));
[...]
}
Let's assume that all is simplified up to here but works.
So in the test, I'd like to inspect the argument given to sendMessage in the function writeDataToRemote.
I read about ::testing::SaveArg and ::testing::SaveArgPointee on StackOverflow (but not in the documentation, though).
TEST(SomeClassTest, writesMessageToSocket){
MockTcp mockTcp;
SomeClass sc(mockTcp);
// >>>how to declare msgArg here?<<<
EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::SaveArgPointee<0>(msgArg));
const auto derivedMsg = std::make_shared<DerivedMessage>();
sc.writeDataToRemote(derivedMsg);
// further inspection of msgArg follows
}
As written in the code comment, I don't know how to declare the msgArg variable so that it can be assigned the actual argument given to sendMessage. When using SaveArg I think I'd get a dangling pointer and doing it as above I get errors because the message cannot be copy-assigned. Any hints apreciated.
In your case you actually want to just save and inspect the considered shared_ptr, so it is enough to use SaveArg:
MockTcp mockTcp;
SomeClass sc(mockTcp);
std::shared_ptr<BaseMessage> bm;
EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::SaveArg<0>(&bm)); // it will effectively do bm = arg;
const auto derivedMsg = std::make_shared<DerivedMessage>();
sc.writeDataToRemote(derivedMsg);
// verify that the argument that you captured is indeed pointing to the same message
std::cout << derivedMsg.get() << std::endl;
std::cout << bm.get() << std::endl;
The common misunderstanding of SaveArgPointee is that it assigns value pointed by the arg to your local variable in test, which in your case maybe is not a good idea, because it would invoke a copy constructor of Message.
Alternatively I can recommend using Invoke. It is very generic and easy to use. You can e.g. capture the desired argument like that:
MockTcp mockTcp;
SomeClass sc(mockTcp);
std::shared_ptr<BaseMessage> bm;
EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(::testing::Invoke([&bm](auto arg) { bm = arg; }));
const auto derivedMsg2 = std::make_shared<DerivedMessage>();
sc.writeDataToRemote(derivedMsg2);
std::cout << derivedMsg2.get() << std::endl;
std::cout << bm.get() << std::endl;
Or using a raw pointer to BaseMessage:
BaseMessage* rawBm = nullptr;
EXPECT_CALL(mockTcp, sendMessage(_)).Times(1).WillOnce(Invoke([&rawBm](auto arg) { rawBm = arg.get(); }));
const auto derivedMsg2 = std::make_shared<DerivedMessage>();
sc.writeDataToRemote(derivedMsg2);
std::cout << derivedMsg2.get() << std::endl;
std::cout << rawBm << std::endl;

Returning std::unique_ptr to abstract type with custom deleter from a memory pool

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.

How to do actions on members of child class templates from an abstact base class?

I know this question gets asked a lot, but I have a specific use case, so I don't think it's a duplicate!
I have an abstract base class:
template<int N>
class Child;
class Base
{
public:
// Factory-like generation of children as Base
static Ptr<Base> New(int baseN)
{
if (baseN == 2) return new Child<2>();
else if (baseN == 3) return new Child<3>()
}
// Update
virtual void update() = 0;
};
And I'm writing some children of Base as class templates (on an int):
template<int N>
class Child
:
public Base
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
// Implement update
virtual void update();
// Should call the passed callable on m_member
virtual void execute(std::function<void(Matrix<N>&)>&);
};
// Force compilation of Child<N> for some values of N (of interest, including 3) here
// Then,
int baseN = 3;
Ptr<Base> obj = Base::New(baseN); // will get me a Child<3> as a Base object
auto callable = [](Matrix<3>) ->void {};
// Can I access Child<3>::m_member ??
// Can't cast to Child<baseN> (baseN is not constexpr) and don't want to
// But want to do something like:
obj->execute(callable);
// Which forwards 'callable' to the method from concrete type, probably using a cast?
In short, I need to have some sort of access to m_member from the declared Base object.
Preferably, a way to call Child<N>::execute from Base without making Base a template on N too.
Things I've tried/thought-of include:
'Type erasure' of Matrix<N> by hiding them behind an interface, but because Matrix<N>'s interface strongly depends on N, doing that renders the classes useless (think: Vector<N>& Matrix<N>::diag() for example)
Can Base::New do anything to record what concrete type it creates? I doubt that because types are not objects.
EDIT: (Btw this is C++11)
So, I accidentally figured out a way to do this; but I don't quite understand why the following works (Not well versed into assembly yet):
I'm using a Database for objects (unordered_map<string, object*> where object is a class that every registered object has to inherit from).
When a Child is created, we register it to a database with a name of Child<N>.
Then, at application-level code, there is a findChild<int N> template which employs compile-time recursion to find which concrete class was the Base pointer created from (At runTime, by dynamicCasting and testing). When It finds it, it can cast it to void* through a static method (findChild<N>::castToConcrete)
What's interesting is that we can somehow use findChild<0> to access the findChild<N> in question if Child<N> is polymorphic. This forces us to have at most one object of Child (for all possible Ns) and I certainly can live with that.
You can see and inspect a minimal code example here: https://onlinegdb.com/CiGR1Fq5z
What I'm so confused about is that Child<0> and other Child<N> are completely different types; So how can we access one's members from a pointer to another type? I'm most likely relying on UB and even fear there is a stack smacking of some sort!
For reference, I'm including the code here in case the link dies.
#include <unordered_map>
#include <vector>
#include <functional>
#include <iostream>
using namespace std;
#ifndef MAX_N_VALUE
#define MAX_N_VALUE 10
#endif // !MAX_N_VALUE
// ------------------ Lib code
// A dummy number class for testing only
template <int N> struct Number { constexpr static int value = N; };
// Objects to register to the database
struct object
{
// Members
string name;
// construction/Destruction
object(const string& name) : name(name) {}
virtual ~object(){};
};
// Database of objects
struct DB
: public unordered_map<string, object*>
{
// See if we can the object of name "name" and type "T" in the DB
template <class T>
bool found(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return true;
cout << name << " found but it's of another type." << endl;
return false;
}
cout << name << " not found." << endl;
return false;
}
// Return a const ref to the object of name "name" and type "T" in the DB
// if found. Else, fails
template <class T>
const T& getObjectRef(const string& name) const
{
unordered_map<string,object*>::const_iterator iter = find(name);
if (iter != end())
{
const T* ptr = dynamic_cast<const T*>(iter->second);
if (ptr) return *ptr;
cout << name << " found but it's of another type." << endl;
abort();
}
cout << name << " not found." << endl;
abort();
}
};
// Forward declare children templates
template<int N>
class Child;
// The interface class
struct Base
{
// Construction/Destruction
protected:
static unsigned counter;
Base(){}
public:
virtual ~Base() {}
// Factory-like generation of children as Base
// THIS New method needs to know how to construct Child<N>
// so defining it after Child<N>
static Base* New(int baseN, DB& db);
// Update
virtual void update() = 0;
// Call a callable on a child, the callable interface
// however is independent on N
virtual void execute(std::function<void(Base&)>& callable)
{
callable(*this);
}
};
unsigned Base::counter = 0;
// The concrete types, which we register to the DB
template<int N>
struct Child
:
public Base, public object
{
// members
vector<Number<N>> member;
// Construction/Destruction
Child() : Base(), object(string("Child") + to_string(N) + ">"), member(N, Number<N>()) {}
virtual ~Child() {}
// Test member method (Has to be virtual)
virtual vector<Number<N>> test() const
{
cout << "Calling Child<" << N << ">::test()" << endl;
return vector<Number<N>>(N, Number<N>());
}
// Implement update
virtual void update()
{
cout << "Calling Child<" << N << ">::update()" << endl;
};
};
// New Base, This can be much more sophisticated
// if static members are leveraged to register constructors
// and invoke them on demand.
Base* Base::New(int baseN, DB& db)
{
if (baseN == 2)
{
Child<2>* c = new Child<2>();
db.insert({string("Child<")+std::to_string(2)+">", c});
return c;
}
if (baseN == 3)
{
Child<3>* c = new Child<3>();
db.insert({string("Child<")+std::to_string(3)+">", c});
return c;
}
return nullptr;
}
// Finder template for registered children
template<int N>
struct findChild
{
// Concrete Type we're matching against
using type = Child<N>;
// Stop the recursion?
static bool stop;
// Compile-time recursion until the correct Child is caught
// Recursion goes UP in N values
static void* castToConcrete(const DB& db, Base* system)
{
if (N > MAX_N_VALUE) stop = true;
if (stop) return nullptr;
if (db.found<type>(string("Child<")+to_string(N)+">"))
{
type* ptr = dynamic_cast<type*>(system);
return static_cast<void*>(ptr);
}
// NOTE: This should jump to the next "compiled" child, not just N+1, but meh;
return findChild<N+1>::castToConcrete(db, system);
}
};
// Activate recursive behaviour for arbitraty N
template<int N>
bool findChild<N>::stop = false;
// Explicit specialization to stop the Compile-time recursion at a decent child
template<>
struct findChild<MAX_N_VALUE+1>
{
using type = Child<MAX_N_VALUE+1>;
static bool stop;
static void* castToConcrete(const DB& t, const Base* system)
{
return nullptr;
}
};
// Disactivate recursive behaviour for N = 11
bool findChild<MAX_N_VALUE+1>::stop = true;
// ------------------ App code
int main()
{
// Create objects database
DB db;
// --- Part 1: Application writers can't write generic-enough code
// Select (from compiled children) a new Base object with N = 2
// and register it to the DB
Base* b = Base::New(2, db);
b->update();
cout << "Access children by explicit dynamic_cast to Child<N>:" << endl;
// Get to the object through the objects DB.
// Child destructor should remove the object from DB too, nut meh again
const auto& oo = db.getObjectRef<Child<2>>("Child<2>");
cout << oo.test().size() << endl;
// --- Part 2: Application writers can write generic code if the compile
// Child<N> for their N
cout << "If Child<N> is polymorphic, we can access the correct child from findChild<0>:" << endl;
// Create a lambda that knows about db, which Base applies on itself
function<void(Base&)> lambda = [&db](Base& base) -> void {
// Cast and ignore the result
void* ptr = findChild<0>::castToConcrete(db, &base);
// Cast back to Child<0>
findChild<0>::type* c = static_cast<findChild<0>::type*>(ptr);
// Now access original Child<N> methods and members from Child<0>
cout << "Method:\n" << c->test().size() << endl;
cout << "Member:\n" << c->member.size() << endl;
};
b->execute(lambda);
return 0;
}
I compiled with GCC 9 with the following options:
-m64 -Wall -Wextra -Wno-unused-parameter -Wold-style-cast -Wnon-virtual-dtor -O0 -fdefault-inline -ftemplate-depth-200
It seems you want inheritance to group not so related classes...
std::variant (C++17) might be more appropriate:
template<int N>
class Child
{
// Member, N is not the size of matrix, more like the size of a component in matrix
Matrix<N> m_member;
public:
void update();
void execute(std::function<void(Matrix<N>&)> f) { f(m_member); }
};
using Base = std::variant<Child<2>, Child<3>>;
and then:
void foo(Base& obj)
{
struct Visitor {
template <std::size_t N>
void operator()(Child<N>& c) const
{
auto callable = [](Matrix<N>) -> void {/*..*/};
c.execute(callable);
}
} visitor;
std::visit(visitor, obj);
}
To answer to your Edit, whereas your callable take a Base, you might chain the dynamic_cast as follow:
template <int N>
void foo_base(Base& b)
{
if (auto* child = dynamic_cast<Child<N>*>(&b)) {
// Job with Child<N>
std::cout << "Method:" << child->test().size() << std::endl;
std::cout << "Member:" << child->member.size() << std::endl;
}
}
template <int... Ns>
void foo_dispatch(std::integer_sequence<int, Ns...>, Base& base)
{
//(foo_base<Ns>(base), ...); // C++17
const int dummy[] = {0, (foo_base<Ns>(base), 0)...};
static_cast<void>(dummy); // Avoid warning about unused variable
}
With a call similar to:
function<void(Base&)> lambda = [](Base& base) {
//foo_dispatch(std::integer_sequence<int, 2, 3>(), base);
foo_dispatch(std::make_integer_sequence<int, MAX_N_VALUE>(), base);
};
Demo
(std::integer_sequence is C++14, but can be implemented in C++11)
Note: Jarod's answer is still a little bit better if you know possible
values of N in Child<N> at compile-time and don't want to provide a way to extend them. Plus, of course, if you can use C++17.
Here I'm relying on "Similar types" defined by the standard as:
4.4 Qualification conversions [conv.equal]
... trimmed ...
Two pointer types T1 and T2 are similar if there exists a type T and integer n > 0 such that:
T1 is cv(1,0) pointer to cv(1,1) pointer to ··· cv(1,n−1) pointer to cv(1,n) T
and
T2 is cv(2,0) pointer to cv(2,1) pointer to ··· cv(2,n−1) pointer to (cv2,n) T
where each cv(i,j) is const, volatile, const volatile, or nothing
The same paragraph also shows the conditions for converting expressions.
In short, By inheriting from Base, all Child<N>* pointer types are similar to Base*, hence similar to each other.
Now, we know we can static_cast Child<N> to Child<0> without problems.
But is accessing Child<3> members from a Child<0>* safe?
3.10 Lvalues and rvalues [basic.lval]
If a program attempts to access the stored value of an object through a glvalue of other than one of the
following types the behavior is undefined:
the dynamic type of the object,
... trimmed ...
a type similar (as defined in 4.4) to the dynamic type of the object
There you have it, Accessing the values of Child<3> though a Child<0>* is in fact defined behavior.
This piece of code:
Base* b = Base::New(2);
b->update();
Child<2>* c1 = static_cast<Child<2>*>(b);
c1->update();
cout << c1->t.sValue << " " << c1->t.rValue << endl;
Child<0>* c2 = static_cast<Child<0>*>(b);
c2->update();
cout << c2->t.sValue << " " << c2->t.rValue << endl;
Will actually output (Note the value of the static variable Test<N>::sValue):
Calling Child<2>::update()
Calling Child<2>::update()
2 2
Calling Child<2>::update()
0 2
Static members will always point to Child<0>, and because of that,
Jarod's answer is a better solution for this problem.
But if one wants to allow expanding possible N values, this solution is OK; you just have to remember to put your static variables in Base and not in Child<N>.
Here is a minimal example, showing how to pass a lambda to the Base* while in fact the lambda, casts the pointer to Child<0> and operates on it:
https://onlinegdb.com/TTcMqOmWi

Getting a unique_ptr for a class that inherits enable_shared_from_this

Usually I prefer returning unique_ptr from Factories.
Recently I came to the problem of returning a unique_ptr for a class that inherits enable_shared_from_this. Users of this class may accidentally cause a call to shared_from_this(), though it is not owned by any shared_ptr, which results with a std::bad_weak_ptr exception (or undefined behavior until C++17, which is usually implemented as an exception).
A simple version of the code:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
shared_ptr<Foo> get_shared() {return shared_from_this();}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = pb2->get_shared();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared(); // exception
pb5->doIt();
}
A possible solution is to change the factory method to return shared_ptr but this is not what I'm looking for, as in many cases there is actually no need for sharing and this will make things less efficient.
The question is how to achieve all of the following:
allow the factory to return unique_ptr
allow unique_ptr of this class to become shared
allow shared_ptr of this class to get shared copies (via shared_from_this())
avoid failure when unique_ptr of this class tries to get shared from this (calling get_shared in above example)
Items 1 to 3 are fulfilled with the code above, the problem is with item 4.
The problem with the member function get_shared in the question is that it allows calls by both unique_ptr and shared_ptr with a difficult to distinguish between the two, thus unique_ptr is allowed to call this method and fails.
Moving the get_shared to be a static method which gets the pointer to share from, allows the distinguishing between unique and share which fixes this problem:
class Foo: public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
static shared_ptr<Foo> get_shared(unique_ptr<Foo>&& unique_p) {
return shared_ptr<Foo>(std::move(unique_p));
}
static shared_ptr<Foo> get_shared(const shared_ptr<Foo>& shared_p) {
return shared_p->shared_from_this();
}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior - almost as before
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2 = shared_ptr<Foo>(std::move(pb1));
shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// ok behavior!
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = Foo::get_shared(std::move(pb4));
pb5->doIt();
}
Code: http://coliru.stacked-crooked.com/a/7fd0d462ed486c44
Deriving from enable_shared_from_this is a promise that your instances are owned by a (group of) shared_ptr. Don't lie about this, only ever create shared_ptr<Foo> and never hand out unique_ptr<Foo>.
It's not worth the future pain when you have to disentangle the "safe" uses of unique_ptr<Foo> from the case where a Foo & deep in some logic that wants to call shared_from_this but sometimes is actually a unique_ptr<Foo>.
Use multiple static factory functions and conversion functions. To address your comments, I've added get_shared to support copying a shared pointer. This compiles and is available here: http://ideone.com/UqIi3k
#include <iostream>
#include <memory>
class Foo
{
std::string name;
Foo(const std::string& _name) : name(_name) {}
public:
void doIt() const { std::cout << "Foo::doIt() <" << name << '>' << std::endl;}
virtual ~Foo() { std::cout << "~Foo() <" << name << '>' << std::endl;}
static std::unique_ptr<Foo> create_unique(const std::string & _name) {
return std::unique_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> create_shared(const std::string & _name) {
return std::shared_ptr<Foo>(new Foo(_name));
}
static std::shared_ptr<Foo> to_shared(std::unique_ptr<Foo> &&ptr ) {
return std::shared_ptr<Foo>(std::move(ptr));
}
static std::shared_ptr<Foo> get_shared(const std::shared_ptr<Foo> &ptr) {
return std::shared_ptr<Foo>(std::move(ptr));
}
};
int main() {
// ok behavior
auto pb1 = Foo::create_unique("pb1");
pb1->doIt();
std::shared_ptr<Foo> pb2 = Foo::get_shared(std::move(pb1));
//note the change below
std::shared_ptr<Foo> pb3 = Foo::get_shared(pb2);
pb3->doIt();
// also OK behavior
auto pb4 = Foo::create_unique("pb4");
pb4->doIt();
std::shared_ptr<Foo> pb5 = Foo::to_shared(std::move(pb4)); // no exception now
pb5->doIt();
std::shared_ptr<Foo> pb6 = Foo::create_shared("pb6");
pb6->doIt();
std::shared_ptr<Foo> pb7 = std::shared_ptr<Foo>(pb5);
pb7->doIt();
return 0;
}
That's exactly what I was looking for, making sure that clients may reach a point that sharing is required and it will work transparently without really caring if they are with a shared Pet or with a unique Pet (i.e. making the interface easy to use correctly etc.).
It sounds like the x-y problem to me.
To "make sure that clients can share if required", turn this into a separate tool and put this in your toolset (edit: but it still feels like you have the x-y problem):
namespace tools
{
/// #brief hides the details of sharing a unique pointer
/// behind a controlled point of access
///
/// to make sure that clients can share if required, use this as a
/// return type
template<typename T>
class pointer final
{
public:
// #note: implicit on purpose (to enable construction on return,
// in the client code below)
pointer(std::unique_ptr<T> value);
// #note: implicit on purpose (to enable construction on return,
// in the client code below)
pointer(std::shared_ptr<T> value);
T* const operator->() const { return get(); }
/// #note copy&swap
pointer& operator=(pointer p)
{
using std::swap;
swap(value1, p.value1);
swap(value2, p.value2);
return *this;
}
// example copy
pointer(const pointer<T>& value)
: value1{}, value2{ value.share() }
{
}
// example move
pointer(pointer<T>&& tmp)
: value1{ std::move(tmp.value1) }, value2{ std::move(tmp.value2) }
{
}
/// #note conceptually const, because it doesn't change the address
/// it points to
///
/// #post internal implementation is shared
std::shared_ptr<T> share() const
{
if(value2.get())
return value2;
value2.reset(value1.release());
return value2;
}
T* const get() const
{
if(auto p = value1.get())
return p;
return value2;
}
private:
mutable std::unique_ptr<T> value1;
mutable std::shared_ptr<T> value2;
};
}
Your client code then becomes:
class Foo
{
string name;
Foo(const string& _name) : name(_name) {}
public:
using pointer = tools::pointer<Foo>;
static pointer make_unique(const string& name)
{
return std::make_unique<Foo>(name);
}
void doIt()const {cout << "Foo::doIt() <" << name << '>' << endl;}
virtual ~Foo() {cout << "~Foo() <" << name << '>' << endl;}
};
int main() {
// ok behavior
auto pb1 = Foo::make_unique("pb1");
pb1->doIt(); // call through unique pointer
auto pb2 = pb1.share(); // get copy of shared pointer
auto pb3 = pb1; // get copy of shared pointer
auto pb4 = std::move(pb1); // move shared pointer
}
As you will have found, once an object is managed by a shared_ptr, there is no (safe) way to unshare it. This is by design, since once the lifetime of the object is shared, no one owner can guarantee that it will ever be the sole owner again (except during the execution of the deleter - I'll leave you to reason about whether that's useful to you).
However, the standard library does allow you to specialise any std class template provided it's specialised for a user defined class.
So what you can do is this:
namespace std {
template<class Deleter>
struct unique_ptr<Foo, Deleter> {
static_assert(!std::is_same<Deleter, Deleter>::value, "sorry, not allowed");
// or
static_assert(!sizeof(Deleter), "sorry, not allowed");
// (thanks to Jarod42 && md5i for cleaning up after me)
};
}
And now no unique_ptr can ever own your object (which is clearly designed to be owned only by a shared_ptr).
This is enforced at compile time.
An old thread already, but I stumbled to ponder a question if its always quaranteed that weak_from_this().expired()==true or weak_from_this().use_count() == 0 for an object not managed by shared_ptr - including unique_ptr. If yes, then simple answer to original question could be to realize non-throwing version of shared_from_this() via such checks for objects returned from factory.
May be we can template check of the calling variable ::
class Foo : public enable_shared_from_this<Foo> {
string name;
Foo(const string& _name) : name(_name) {}
public:
static unique_ptr<Foo> create(const string& name) {
return std::unique_ptr<Foo>(new Foo(name));
}
template <typename T>
shared_ptr<Foo> get_shared() { return shared_ptr<Foo>(); }
template <>
shared_ptr<Foo> get_shared<unique_ptr<Foo>>() { return shared_ptr<Foo>(); }
template <>
shared_ptr<Foo> get_shared<shared_ptr<Foo>>() { return shared_from_this(); }
void doIt()const { cout << "Foo::doIt() <" << name << '>' << endl; }
virtual ~Foo() { cout << "~Foo() <" << name << '>' << endl; }
};
int main()
{
// ok behavior
auto pb1 = Foo::create("pb1");
pb1->doIt();
shared_ptr<Foo> pb2{ std::move(pb1) };
shared_ptr<Foo> pb3 = pb2->get_shared<decltype(pb2)>();
pb3->doIt();
// bad behavior
auto pb4 = Foo::create("pb4");
pb4->doIt();
shared_ptr<Foo> pb5 = pb4->get_shared<decltype(pb4)>(); // exception
if (pb5 != nullptr)
pb5->doIt();
return 0;
}
I am not sure if that is exactly what you want, but might solve the point 4 you have mentioned.

Python with statement in C++

I am trying to implement something similar to the Python with statement in C++. As I plan to use it mainly with Qt-OpenGL the methods are called bind and release (in Python __enter__, __exit__).
Code I came up with:
header:
#include <iostream>
#include <vector>
class With
{
public:
class A
{
public:
virtual ~A() { }
};
template <typename T>
class B : public A
{
public:
B(T& _t) : t(_t)
{
t.bind();
}
virtual ~B()
{
t.release();
}
T& t;
};
template <typename... Args>
With(Args&... args)
{
set(args...);
}
~With();
template <typename T, typename... Args>
void set(T& t, Args&... args)
{
set(t);
set(args...);
}
template <typename T>
void set(T& t)
{
a.push_back(dynamic_cast<A*>(new B<T>(t)));
}
std::vector<A*> a;
};
cpp:
With::~With()
{
for (auto it = a.begin(); it != a.end(); ++it)
{
delete *it;
}
}
Usage:
class X
{
public:
void bind() { std::cout << "bind x" << std::endl; }
void release() { std::cout << "release x" << std::endl; }
};
class Y
{
public:
void bind() { std::cout << "bind y" << std::endl; }
void release() { std::cout << "release y" << std::endl; }
};
int main()
{
X y;
Y y;
std::cout << "start" << std::endl;
{
With w(x, y);
std::cout << "with" << std::endl;
}
std::cout << "done" << std::endl;
return 0;
}
Questions:
Needing class A and class B feels a bit clumsy. Is there a better alternative?
Are there any draw backs in using && instead of &? It would make the usage of tempory objects possible (e.g. With w(X(), y);)
The with statement is a way to do in python what is already the normal thing in C++. It is called RAII: Resource acquisition is initialization.
In python, when a class object is created, the __init__ method is called (but this is not a strict guarantee). The __del__ method is called by the garbage collector at some point after the object is no longer in use, but it is not deterministic.
In C++ the destructor is called at a well defined point so there is no need for with.
I suggest you just use something like class B (no need for class A or With).
template <typename T>
class B {
public:
B(T& t) : m_t(t){
m_t.bind();
}
~B() {
m_t.release();
}
T& m_t;
}
use it like this:
{
B<X> bound_x(x); // x.bind is called
B<Y> bound_y(y); // y.bind is called
// use x and y here
} // bound_x and bound_y is destroyed here
// so x.release and y.release is called
It ships with the language, and it's called RAII.
struct X {
X() { std::cout << "bind\n"; }
~X() { std::cout << "release\n"; }
};
int main() {
X x;
}
One possible solution:
template <typename T>
void with(T *t, std::function<void ()> fn) {
t->bind();
fn();
t->unbind();
}
Usage:
with(object, []() {
// object bound
});
While I agree with the answers here that RAII is the C++ way to manage resource life-cycles, I personally find RAII not robust enough to handle all scenarios. I find that the constructor/destructor paradigm is good enough for memory resource management. For other resources (eg. file descriptors, sockets, timers etc) using an explicit resource management block provides more robustness. My reasoning is as follows -
Assume your resource is a file descriptor. You want to close it in the destructor but some IO error occurred. What do you do? Throwing an exception from a destructor is a very bad choice. Just ignoring the error is probably just as bad. For situations like this other languages give resource block mechanism to decouple resource management from object lifecycle.
C++ already faces this issue in its standard library. The std::mutex lock and unlock methods are essentially resource holders. However the lifecycle of std::mutex cannot be tied to lock/unlock. So we have a wrapper class std::lock_guard solely for lock/unlock RAII purpose. While an elegant solution, the problem is this lacks generality. Imagine every resource-management related class coming up with its own wrapper class. If we had a standard defined resource-management mechanism we could probably uniformly do this with a single wrapper template.
I hope this convinces RAII proponents that a standard specified resource-management model on top of RAII paradigm would be good.
Coming to the question about Python with clause: A very naive implementation would be something as follows:
// Standardised interface for resource managers.
template<typename T>
concept Withable = requires(T t) {
{ t.bind() } -> std::same_as<void>;
{ t.release() } -> std::same_as<void>;
};
// Universal wrapper for all resource managers.
template<Withable T>
struct WithWrapper {
T* ref_;
WithWrapper(T& obj)
: ref_{&obj}
{ ref_->bind(); }
~WithWrapper() { ref_->release(); }
T& get() { return *ref_; }
};
// In case we want the with keyword.
#define with(...) if (__VA_ARGS__; true)
Usage for your case would be -
// Making sure your types are compatible.
static_assert(Withable<X>);
static_assert(Withable<Y>);
// Using the with and wrapper.
int main() {
X y;
Y y;
// With my naive implementation it's not really possible to declare two
// separate types in same initialisation block. However even with two
// "with"s, the execution behaviour is extacly the same as Python.
with (auto xw = WithWrapper(x)) { with (auto yw = WithWrapper(y)) {
// Do something with xw and yw ...
} }
}