Is there something like following in c++:
https://kotlinlang.org/docs/reference/null-safety.html#safe-calls
I want to shorten calls like following:
int x = 0;
IPtr pClass(...);
if (pClass)
{
pClass->...
pClass->...
x = pClass->function();
}
Any macro/language trick I can use to make this look like following pseudo code?
IPtr pClass(...);
pClass?->... // only call function if pClass != nil
pClass?->... // only call function if pClass != nil
int x = pClass?->function() | 0; // only call function if pClass != nil, otherwise assign 0 to x
Edit - UseCase
I develop a few plugins for another software and other plugins of myself may be available or not.
Most simple example would be a logging plugin, where I want to have a lot of logging calls all over in my code and want to log something only, if the logging module was loaded and is available. I get a pointer to the singleton logger module from the software my plugin is for. My code would be polluted by log lines like following:
if (logger)
{
logger->log(...);
}
And it would be more beautiful and compact to make this a one liner without the if that is null safe...
Code style solution (The RIGHT solution)
The design could be improved to solve this issue. When the logger
plugin is not loaded, you shouldn't receive a nullptr
but rather a dummy logger
object that has an empty implementation.
Factories (especially ones creating global infrastructure objects) should not return nullptr
.
Smart pointer wrapper
This is a concept you could use:
struct Object {
void run() { std::cout << "run" << std::endl; }
void stop() { std::cout << "stop" << std::endl; }
};
template < typename T >
struct safe_ptr : std::unique_ptr<T> {
safe_ptr(T * ptr) : std::unique_ptr<T>(ptr ? ptr : &t) {}
virtual ~safe_ptr() {
if (::std::unique_ptr<T>::get() == &t)
::std::unique_ptr<T>::release();
}
using std::unique_ptr<T>::operator*;
using std::unique_ptr<T>::operator->;
private:
T t;
};
int main() {
safe_ptr<Object> safe(nullptr);
safe->run();
}
The safe_ptr<T>
will use a valid pointer to an object if initialized using a nullptr
.
You could of course improve this solution to work only with Objects that define a default fallback static object, e.g:
struct Object {
void run() { std::cout << "run" << std::endl; }
void stop() { std::cout << "stop" << std::endl; }
static Object fallback;
};
Object Object::fallback;
template < typename T >
struct safe_ptr : std::unique_ptr<T> {
safe_ptr(T * ptr) : std::unique_ptr<T>(ptr ? ptr : &T::fallback) {}
virtual ~safe_ptr() {
if (::std::unique_ptr<T>::get() == &T::fallback)
::std::unique_ptr<T>::release();
}
using std::unique_ptr<T>::operator*;
using std::unique_ptr<T>::operator->;
};
This will avoid multiple allocations of the private T t
and will allow a specific initialization of the fallback
object.
Not the solution you're suggesting, but since I personally find these "safe" call operators particularly hard to follow I'll suggest an alternative code style based on a lambda called on the spot:
int const x = [&] {
IPtr const pClass = /*...*/;
if(!pClass)
return 0;
pClass->/*...*/;
pClass->/*...*/;
return pClass->function();
}();
This gizmo is called an IIFE by Javascipt folks, and is incredibly useful to wrap complicated initializations with branching code paths.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With