How to RAIIfy this common pattern?

Pages: 12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Foo foo;
//Bar bar;
//Baz baz;
{
    auto old = foo.get_snafu();
    foo.set_snafu(x);
    //...
    foo.set_snafu(old);
}
{
    auto old = bar.get_qux();
    bar.set_qux(y);
    //...
    bar.set_qux(old);
}
{
    auto old = baz.quux;
    baz.quux = z;
    //...
    baz.quux = old;
}
Is it possible to rewrite this into something like
1
2
3
4
5
6
7
8
9
10
11
12
{
    MAGIC1(foo, snafu, x);
    //...
}
{
    MAGIC1(bar, qux, y);
    //...
}
{
    MAGIC2(baz, quux, z);
    //...
}
?
What about something like this?
1
2
3
4
5
6
7
#define MAGIC1(obj, var, val) \
    do { \
        auto old = obj.get_##var(); \
        obj.set_##var(val); \
        //... \
        obj.set_##var(old); \
    } while(0) 

Last edited on
That doesn't use RAII.
Do you have any ideas?
I wouldn't be asking a question if I did, would I?
You would essentially need an object that can store object, getter, setter, and value. The std::function and std::mem_fn seem to do part of that, so I'd guess it is possible.

Such object declaration is still longish, but perhaps a macro can trim it down as you have the "get_" and "set_" patterns?
I wouldn't be asking a question if I did, would I?

I don't know you, buddy, nor do I care to.

Anyway, you need to learn how to ask questions better.
Put in more effort next time.
keskiverto: Hmm... Would it be possible to detect automatically if the class has setters and getters of the expected name?
1
2
3
4
    auto old = baz.quux;
    baz.quux = z;
    //...
    baz.quux = old;

not sure to understand, ¿you want to keep the state that you reach in ... from altered `quux' but maintain the original `quux'?

¿how is this common?
Sorry, maybe that wasn't clear enough. Here's an example:
1
2
3
4
auto old_palette = screen.get_palette();
screen.set_palette(options_screen_palette);
display_options_screen(); //may not return for several seconds
screen.set_palette(old_palette);

Basically I'm encountering a lot of situations where I need to override some value only for the duration of a function or section of code, and then return that value to its previous value once that function returns.
How about something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class override_screen_palette
{
  palette_type old_palette; // for storing old palette
  // constructor
  override_screen_palette(screenType screen, palette_type overridePalette)
 {
    palette_type old_palette = screen.get_palette();
    screen.set_palette(overridePalette);
    };

  //destructor
  ~override_screen_palette)(
  {
     screen.set_palette(old_palette);
   }
}


used like this:
1
2
3
4
5
6
7
8
// here, using old palette
{
  override_screen_palette paletteOverrider(screen, optionsPalette);

  // now, palette has been overridden until scope closes
   display_options_screen(); //may not return for several seconds
}
// scope has closed, destructor has run, using old palette again 


Create the override object anywhere, anywhen. When it destructs (end of scope, end of function, exception thrown etc) the previous palette is put back.

I suppose for your exact needs, there might have to be some templating or macro black magic going on... Or maybe at the point of creation, you can pass in functions that the class uses to get and set.
Last edited on
I suppose for your exact needs, there might have to be some templating or macro black magic going on.
Well, that's kind of the point of the question. Solving this problem for a single property is trivial. The trick is in solving it once for every property.
Here's a rough attempt. The idea is to detect a member or member function of an expected name using SFINAE, and use it to stamp-out a guard object. The guard object just saves the specified state and restores it in its destructor.

The insight in this post is that we can (apparently) use macros to do static reflection in-line by abusing C++17's lambdas.

Usage:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include "guard.hpp"

struct Foo {
  void set_value(int new_value) { value = new_value; }
  int get_value() const { return value; }

private:
  int value = 24;
};

int main() {
  Foo x;
  std::cout << "x.get_value(): " << x.get_value() << '\n';
  {
    // Declare an object named my_guard which saves and restores x.value
    // automatically.
    GUARD(my_guard, x, value);
    // modify and use x.value here
    x.set_value(42);
    std::cout << "x.value has been modified.\n";
    std::cout << "x.get_value(): " << x.get_value() << '\n';

  } // x.value is automagically restored here
  std::cout << "x.value has been restored.\n";
  std::cout << "x.get_value(): " << x.get_value() << '\n';
}


Live demo:
http://coliru.stacked-crooked.com/a/44ae731dc1ed54ed

Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <utility>

#define FORWARD(x) std::forward<decltype(x)>(x)

template <typename T, typename Accessor, typename Mutator,
          typename StateT =
              decltype(std::declval<Accessor>()(std::declval<T &>()))>
struct guard {
  guard(T &x, Accessor const &a, Mutator const &m)
      : object{x}, accessor{a}, mutator{m}, state{accessor(object)} {}
  ~guard() { mutator(object, state); }

  guard(guard const &) = delete;
  guard(guard &&) = delete;
  guard &operator=(guard) = delete;
  guard &operator=(guard &&) = delete;

private:
  T &object;
  Accessor accessor;
  Mutator mutator;
  StateT state;
};

template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };

template <typename... Fns> constexpr auto make_overloaded(Fns &&... fns) {
  return overloaded<Fns...>{std::forward<Fns>(fns)...};
}

#define EXPECTED_ACCESSOR_NAME(state_name) get_##state_name
#define ACCESSOR_OBJECT(state_name)                                            \
  [](auto &&x) -> decltype(auto) {                                             \
    return make_overloaded(                                                    \
        [](auto &&x,                                                           \
           int) -> decltype(FORWARD(x).EXPECTED_ACCESSOR_NAME(state_name)()) { \
          return FORWARD(x).EXPECTED_ACCESSOR_NAME(state_name)();              \
        },                                                                     \
        [](auto &&x...) -> decltype(FORWARD(x).state_name) {                   \
          return FORWARD(x).state_name;                                        \
        })(FORWARD(x), 0);                                                     \
  }
#define EXPECTED_MUTATOR_NAME(state_name) set_##state_name
#define MUTATOR_OBJECT(state_name)                                             \
  [](auto &&x, auto &&new_state) -> decltype(auto) {                           \
    return make_overloaded(                                                    \
        [](auto &&x, auto &&new_state, int)                                    \
            -> decltype(FORWARD(x).EXPECTED_MUTATOR_NAME(state_name)(          \
                FORWARD(new_state))) {                                         \
          return FORWARD(x).EXPECTED_MUTATOR_NAME(state_name)(                 \
              FORWARD(new_state));                                             \
        },                                                                     \
        [](auto &&x, auto &&new_state,                                         \
           ...) -> decltype(FORWARD(x).state_name = FORWARD(new_state)) {      \
          return FORWARD(x).state_name = FORWARD(new_state);                   \
        })(FORWARD(x), FORWARD(new_state), 0);                                 \
  }

#define GUARD(guard_name, object_name, state_name)                             \
  guard guard_name {                                                           \
    object_name, ACCESSOR_OBJECT(state_name), MUTATOR_OBJECT(state_name)       \
  } 

Last edited on
I feel like you could use pointers to members to do away with all the macro stuff, right?
But why would you do that when you could use a enormously overengineered solution? ;)

The macro junk gives the dubious benefit of allowing detection tests in-line, such that @helios' MAGIC1 and MAGIC2 can both be replaced by GUARD. If you were willing to do away with that, then I believe you're right, like @Repeater hinted:
Or maybe at the point of creation, you can pass in functions that the class uses to get and set.


Edit:
If you want that, instead of the GUARD macro, write
guard my_guard {x, std::mem_fn(&foo::get_value), std::mem_fn(&foo::set_value) };
Last edited on
Nice. I'll take a look at this later.
Aw... Valiant attempt, but it doesn't compile on MSVC 2015. Still, you get full marks on my book.
A'ight, this is my stab at it. It's not that great. It only works if the setters and getters have specific signatures (which isn't too much of a problem in my case) and I wasn't able to unify MAGIC1 and MAGIC2 into a single macro:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#include <utility>
#include <type_traits>
#include <iostream>

template <typename T, typename MemberT>
class Guard1{
public:
	typedef const MemberT &(T::*getter)() const;
	typedef void (T::*setter)(const MemberT &) ;
private:
	T *obj;
	setter s;
	MemberT old;

	void release(){
		if (!this->obj)
			return;
		(this->obj->*this->s)(old);
		this->obj = nullptr;
	}
public:
	Guard1(): obj(nullptr){}
	Guard1(T &obj, const MemberT &val, getter g, setter s): old((obj.*g)()){
		this->obj = &obj;
		this->s = s;
		(this->obj->*this->s)(val);
	}
	Guard1(Guard1 &&other): old(std::move(other.old)){
		this->obj = other.obj;
		other.obj = nullptr;
		this->s = other.s;
	}
	Guard1(const Guard1 &other) = delete;
	~Guard1(){
		this->release();
	}
	const Guard1 &operator=(Guard1 &&other){
		this->release();
		this->old = std::move(other.old);
		this->obj = other.obj;
		other.obj = nullptr;
		this->s = other.s;
		return *this;
	}
};

template <typename T, typename MemberT>
class Guard2{
public:
	typedef MemberT T::*member;
private:
	T *obj;
	member m;
	MemberT old;

	void release(){
		if (!this->obj)
			return;
		this->obj->*this->m = std::move(this->old);
		this->obj = nullptr;
	}
public:
	Guard2(): obj(nullptr){}
	Guard2(T &obj, const MemberT &val, member m): old(obj.*m){
		this->obj = &obj;
		this->m = m;
		this->obj->*this->m = val;
	}
	Guard2(Guard2 &&other): old(std::move(other.old)){
		this->obj = other.obj;
		other.obj = nullptr;
		this->m = other.m;
	}
	Guard2(const Guard2 &other) = delete;
	~Guard2(){
		this->release();
	}
	const Guard2 &operator=(Guard2 &&other){
		this->release();
		this->old = std::move(other.old);
		this->obj = other.obj;
		other.obj = nullptr;
		this->m = other.m;
		return *this;
	}
};

template <typename T, typename R>
R get_ret_type(const R &(T::*)() const){
	return R();
};

template <typename T, typename R>
R get_ret_type(R (T::*)() const){
	return R();
};

#define MAGIC1(obj, prop, val) \
	Guard1<decltype(obj), decltype(get_ret_type(&decltype(obj)::get_##prop))> guard_##__COUNTER__(obj, val, &decltype(obj)::get_##prop, &decltype(obj)::set_##prop)

#define MAGIC2(obj, prop, val) \
	Guard2<decltype(obj), decltype(decltype(obj)::prop)> guard_##__COUNTER__(obj, val, &decltype(obj)::prop)

#define DEFINE_GETTER(x) \
	const decltype(x) &get_##x() const{ \
		return this->x; \
	}

//------------------------------------------------------------------------------

#define DEFINE_NON_CONST_GETTER(x) \
	decltype(x) &get_##x(){ \
		return this->x; \
	}

#define DEFINE_GETTER_SETTER(x) \
	DEFINE_GETTER(x) \
	void set_##x(const decltype(x) &value){ \
		this->x = value; \
	}

class A{
	int i = 0;
public:
	DEFINE_GETTER_SETTER(i)
};

class B{
	double x = 0;
public:
	B() = default;
	explicit B(double x): x(x){}
	DEFINE_GETTER_SETTER(x)
};

std::ostream &operator<<(std::ostream &stream, const B &b){
	return stream << "B(" << b.get_x() << ")";
}

class C{
	B b;
public:
	C() = default;
	C(const B &b): b(b){}
	DEFINE_GETTER_SETTER(b)
};

struct D{
	int j = 0;
};

//------------------------------------------------------------------------------

int main(){
	A a;
	B b;
	C c;
	D d;

	{
		std::cout << a.get_i() << std::endl;
		{
			MAGIC1(a, i, 42);
			std::cout << a.get_i() << std::endl;
		}
		std::cout << a.get_i() << std::endl;
	}
	{
		std::cout << b.get_x() << std::endl;
		{
			MAGIC1(b, x, 3.141592);
			std::cout << b.get_x() << std::endl;
		}
		std::cout << b.get_x() << std::endl;
	}
	{
		std::cout << c.get_b() << std::endl;
		{
			MAGIC1(c, b, B(2.718282));
			std::cout << c.get_b() << std::endl;
		}
		std::cout << c.get_b() << std::endl;
	}
	{
		std::cout << d.j << std::endl;
		{
			MAGIC2(d, j, 24);
			std::cout << d.j << std::endl;
		}
		std::cout << d.j << std::endl;
	}
	return 0;
}
Last edited on
Hi helios,
I'm not sure about the requirements you have... but say, in general, RAII is to put the restoring part in the destructor.

To make it simple, I'll create an interface RestoreStatus with a function store() and restore().
Then for any class I want to have the RAII with the "restore previous state" function, I will inherit with RestoreStatus.

I have to implement the store() and restore() functions for myClass and then, in my code, I'll do :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cassert>

class RestoreStatus
{
public:
	virtual void store() = 0;
	virtual void restore() = 0;
};

class MyClass : public RestoreStatus
{
public:
	//... implement store() and restore() of the status
	void store() { savedStatus = status; }
	void restore() { status = savedStatus; }

public:
	int status;
	int savedStatus;
};

class MyClassStatusRestore
{
public:
	MyClassStatusRestore(RestoreStatus& aO)
	:	o(aO)
	{
		o.store();
	}
	~MyClassStatusRestore()
	{
		o.restore();
	}
	RestoreStatus& o;
};

void f()
{
	MyClass myObjectToBeRestored;
	int const initialStatus = 1;
	myObjectToBeRestored.status = initialStatus;
	{
		MyClassStatusRestore restoreThatAfterwardPliiiiiiiiiZ(myObjectToBeRestored);
		int const changeStatus = -1;	// parallel Universe
		myObjectToBeRestored.status = -changeStatus;
	}
	assert(initialStatus == myObjectToBeRestored.status);
}


int main()
{
	f();
//--
	return 0;
}

It's the general idea using natural OOP.
Is it what you look for ? or some very more clever solution ?

You can see in my example that I followed the GOOOOOOOOOOOOOOOOOD naming convention ^_^~
Last edited on
I'm not sure about the requirements you have.
Okay, stop right there. Why are you replying if, by your own admission, you don't understand the question?
Pages: 12