Reputation: 43
Is there a way to call a class member function automatically in the end of a scope? Apparently if the class is instantiated within the same scope, clean() can be used in the destructor of it. The question is, can we achieve that if it is instantiated before the scope? In detail:
class foo
{
public:
void do_something() {}
void clean() {}
};
int main()
{
foo c;
{
c.do_something();
// do something
// call c.clean() automatically
}
}
Upvotes: 1
Views: 646
Reputation: 11271
std::unique_ptr
actually has something like that, in the form of a second parameter you can pass to the constructor, a deleter. The deleter cleans up when the std::unique_ptr
object goes out of scope. Normally (i.e. if you don't specify it) it would be std::default_delete
that calls delete
on the dynamically allocated memory it owns. But you can make it do other things, like this:
#include <cstdio>
#include <memory>
class foo
{
public:
void do_something() { printf("do_something\n"); }
void clean() { printf( "clean\n"); }
};
int main()
{
foo c;
{
std::unique_ptr<foo, void(*)(foo*)> scoped_cleaner(&c, [](foo* c) { c->clean(); });
c.do_something();
}
}
Upvotes: 4
Reputation: 238351
Only thing that is called automatically at the end of the scope is the destructors of the objects whose lifetime end in that scope. As such, you could have another object local to the inner scope whose destructor calls the function.
A generic solution exists in Boost already:
foo c;
{
BOOST_SCOPE_EXIT(&c) {
c.clean();
};
c.do_something();
// do something
}
One caveat with all these answers including mine is that foo::clean()
must not throw.
Upvotes: 2
Reputation: 180630
Write a do_guard
. You can leverage RAII to create a wrapper that will call do
on the object you give the wrapper in it's constructor, and then the destructor will call clear
. That would look like
struct do_guard
{
foo& ref;
do_guard(foo& ref) : ref(ref) { ref.do_something(); }
~do_guard() { ref.clean(); }
};
int main()
{
foo c;
{
do_guard guard(c);
// do something
} // guard.~do_guard() will call c.clean() automatically
}
Upvotes: 1
Reputation: 122468
You can make do_something
return something that gets its destructor called at the end of the scope:
class foo;
struct cleaner {
foo& f;
cleaner(foo& f) : f{f} {}
~cleaner();
};
class foo
{
public:
cleaner do_something() { return *this; }
void clean() {}
};
cleaner::~cleaner() { f.clean(); }
int main()
{
foo c;
{
auto x = c.do_something();
// do something
} // x calls c.clean() automatically
}
Upvotes: 0
Reputation: 87959
Something like this. May not be exactly what you are looking for as it requires you do declare another variable at the start of the scope where you want the clean function to be called.
class CleanFoo
{
public:
CleanFoo(Foo& r) : ref(r) {}
~CleanFoo() { ref.clean(); }
CleanFoo(const CleanFoo&) = delete;
CleanFoo& operator=(const CleanFoo&) = delete;
private:
Foo& ref;
};
int main()
{
foo c;
{
CleanFoo cc(c);
...
} // c.clean() will be called here
...
}
Upvotes: 5