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
andclass 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);
)
Advertisement
Answer
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