I know that RVO is mainly used, but can I count on it?
Do not rely on RVO for logic. Simply put, compiling your program can be disabled using the command line.
Is there any way to achieve this?
Surprisingly, the standard library already gives you this functionality, so you do not need to risk implementing it yourself (moving constructors and operators, as you know, is difficult to obtain).
std::unique_ptr with user deletion does the job nicely.
#include <iostream> #include <memory> #include <cassert> // test type struct X { bool flag = false; }; // a custom deleter that sets a flag on the target struct flag_setter_impl { template<class X> void operator()(X* px) const { if (px) { assert(!px->flag); std::cout << "setting flag!" << std::endl; px->flag = true; } } }; // a type of unique_ptr which does not delete, but sets a flag template<class X> using flag_setter = std::unique_ptr<X, flag_setter_impl>; // make a flag_stter for x template<class X> auto make_flag_setter(X& x) -> flag_setter<X> { return flag_setter<X>(&x, flag_setter_impl()); } // quick test auto main() -> int { using namespace std; X x; { auto fs1 = make_flag_setter(x); auto fs2 = move(fs1); } return 0; }
but i don't have stl on my target
Then do not forget your rules 0, 3, 5
#include <iostream> #include <memory> #include <cassert> // test type struct X { bool flag = false; }; // a custom deleter that sets a flag on the target struct flag_setter_impl { template<class X> void operator()(X* px) const { if (px) { assert(!px->flag); std::cout << "setting flag!" << std::endl; px->flag = true; } } }; // a type of unique_ptr which does not delete, but sets a flag template<class X> struct flag_setter { flag_setter(X* px) : px(px) {} flag_setter(const flag_setter&) = delete; flag_setter(flag_setter&& r) noexcept : px(r.px) { r.px = nullptr; } flag_setter& operator=(const flag_setter& r) = delete; flag_setter& operator=(flag_setter&& r) { flag_setter tmp(std::move(r)); std::swap(tmp.px, px); return *this; } ~flag_setter() noexcept { flag_setter_impl()(px); } private: X* px; }; // make a flag_stter for x template<class X> auto make_flag_setter(X& x) -> flag_setter<X> { return flag_setter<X>(&x); } // quick test auto main() -> int { using namespace std; X x; { auto fs1 = make_flag_setter(x); auto fs2 = move(fs1); } return 0; }
source share