
Hi all, The motivation is to avoid code like the following... //---------------------------------------------------------------------------- #include <iostream> #include <string> struct A { void do_something( std::string s ) const { std::cout << "do something with " << s << " and " << i_ << "\n"; } int i_ = 99; }; // unsafe traditional code struct Unsafe { void set_ref( A& a ) { a_ptr_ = std::addressof(a); } void use_ref( std::string s ) const { if (a_ptr_ != nullptr) { a_ptr_->do_something(s); } } void use_ref_2( std::string s ) const { //forgot to check for nullptr a_ptr_->do_something(s); } A* a_ptr_ = nullptr; //I can't use A& nor reference_wrapper<A>, need to be nullable. }; void f() { A a; Unsafe unsafe; unsafe.use_ref( "hello" ); //null reference, do nothing, hope! unsafe.set_ref(a); unsafe.use_ref( "hello world!" ); //not-null reference, Ok! Unsafe unsafe2; unsafe2.use_ref( "hello" ); //null reference, do nothing, hope! unsafe2.use_ref_2( "hello" ); //null reference, Ops! } //---------------------------------------------------------------------------- The proposed solution: //---------------------------------------------------------------------------- // Proposed (draft) //---------------------------------------------------------------------------- template <typename T> class safe_ref { public: typedef T type; explicit safe_ref() : t_( nullptr ) {} explicit safe_ref(T& t) : t_( std::addressof(t) ) {} template <typename Func> void use ( Func f ) const { if ( is_initialized() ) { f( *t_ ); } } private: bool is_initialized() const { return t_ != nullptr; } T* t_; }; template <typename T> inline safe_ref<T> const ref(T& t) { return safe_ref<T>(t); } template <typename T> inline safe_ref<T const> const cref(T const& t) { return safe_ref<T const>(t); } //---------------------------------------------------------------------------- // Usage //---------------------------------------------------------------------------- #include <iostream> #include <string> struct A { void do_something( std::string s ) const { std::cout << "A::do_something with " << s << " and " << i_ << "\n"; } int i_ = 99; }; struct Safe { void set_ref( A& a ) { a_ref_ = ref(a); } void use_ref( std::string s ) const { a_ref_.use( [&s] ( A& a ) { a.do_something(s); }); } safe_ref<A> a_ref_; }; void usage1() { A a; Safe safe; safe.use_ref( "hello" ); //null reference, do nothing safe.set_ref(a); safe.use_ref( "hello world!" ); //safe reference, Ok! } void usage2() { safe_ref<int> si; si.use( [] (int& i ) { std::cout << i << std::endl; }); int temp = 15; safe_ref<int> si2(temp); si2.use( [] (int& i ) { std::cout << i << std::endl; }); si = ref(temp); si.use( [] (int& i ) { std::cout << i << std::endl; }); } //---------------------------------------------------------------------------- It is similar to optional<T>, but in this case the idea is to not allow access to internal data if the pointer is null, only allowing a safe usage There is interest to add something like this to Boost? Any comments or remarks? Thanks and regards, Fernando Pelliccioni.