Reputation: 372
I'm looking for a mechanic/design pattern, which allows to set up an object in a way, so that the mechanic notices if the object is altered after a certain point of existence (for example construction). Ideally the object would be able to get information about its alteration, as well.
I'm imagining a sort of smart-pointer and/or interface, which notes write access and communicates that to the object.
Possible Use Case: Objects, whose contents have been loaded from file, shall be written to file if altered when destructed.
Trivially you could just implement all setters of the object to count write accesses individually.
class A
{
string filename;
unsigned int altered;
int m_a, m_b, M_c;
public:
A(string filename) : filename(filename), altered(0) { /* parse file */ }
~A() { if(altered) {/* write out to file */} }
void setA(int a) {altered++; m_a = a}
void setB(int b) {altered++; m_b = b}
void setC(int c) {altered++; m_c = c}
};
This I find quite hard to maintain and not very elegant. Also such a solution is not very portable to other kinds of objects.
Upvotes: 0
Views: 50
Reputation: 31
I can not think of any pattern that would somehow magically identify that the file has changed; unless you find it acceptable to make a hash out of the file and then compare the hashes. At some point you will have to change the state of you class so that it writes the altered file. This can be done in a number of ways.
One thing you can implement is a modify
function, which alters the state of the class and gives the user the option to change a mutable version of the class.
void modify(const std::function<void(Mutable_A&)>& modifier) // Implemented in A
{
modifier(/* the internal stucture */);
this->writeFile = []{/* write out to file */}; // Then called in destructor
}
This is then called from the outside like so
a.modify([](auto& a){
a.m_a = 2;
a.m_b = 3;
a.setA(2); // If set is prefered
});
This avoid having to add the arbitrary altered
counter. You can also check if the modifier
callback actually altered and only assign writeFile
if something was altered. The set
functions in this case would only be implemented in Mutable_A
. As to what to call this pattern, I don't know.
Upvotes: 0
Reputation: 122830
I dont think there is a easy generic solution, as you have many decicsions to make. For example in your code you increment altered
even if a==m_a
. This might be just the right thing in some cases, but not in others. Anyhow, here is something simple that would allow you to choose what to do in case the member was modified:
#include <iostream>
using namespace std;
template <typename T>
struct modification_tracking {
using clean_up_t = void(*)(const T&);
modification_tracking(const T& t,clean_up_t clean_up) :
t(t), clean_up(clean_up) {}
~modification_tracking(){ if(modified) clean_up(t); }
void set(const T& v){
modified = t != v;
t = v;
}
private:
T t;
clean_up_t clean_up;
bool modified = false;
};
struct foo {
modification_tracking<int> member{ 1, [](const int& x){ std::cout << x << '\n';}};
};
int main() {
foo f1;
foo f2;
f1.member.set(3);
}
Maybe a smartpointer with a custom deleter can do the same and more in a nicer way. If the objects are lightweight you could even consider to store the original and compare when it goes out of scope. Or compute a hash.. there are really too many options ;)
Upvotes: 1