有没有简单的方法来检查C ++中的不安全表达式? [英] Is there a simple way to check unsafe expression in C++?
问题描述
我正在尝试找到一种[更好]的方式来运行/检查可能不安全的表达式或以更优雅的方式执行多个空检查。
I'm trying to find a [better] way to run/check a potentially unsafe expression or perform multiple null checks in a more elegant way.
这里是我想改善的代码示例:
Here is an example of codes I would like to improve:
if (myObjectPointer &&
myObjectPointer->getSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) {
// Use safely target
... *(myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) ...
}
我试图找到一种更优雅的方法来实现此目的(而不是上面的详细空值检查) )。这是我的第一个想法:
I tried to find a more elegant way to achieve this (instead of the above verbose null checks). Here is my first thoughts:
template<typename T>
bool isSafe(T && function) {
try {
function();
// Just running the func above, but we could e.g. think about returning the actual value instead of true/fase - not that important.
return true;
}
catch (...) {
return false;
}
}
...
// And use the above as follow :
if(isSafe([&](){ myObjectPointer->getSubObject()->getSubSubObject()->getTarget(); })) {
// Use safely target
}
...
上述问题是我们无法捕获信号(分段错误,...)。而且我显然不想处理程序中的所有信号,而只希望处理这个非常具体的check / eval函数。
The problem with the above is that we can't catch signals (Segmentation fault, ...). And I obviously don't want to handle all signals in the program, but only in this very specific check/eval function.
我要解决错误的问题道路 ?还有其他建议吗?还是冗长的if是否不可避免?
I'm I tackling the problem the wrong way ? Any other recommendations ? or the verbose if is inevitable ?
非常感谢。
推荐答案
我正在考虑这一点,就像Jarod42所说的那样,肯定有一些可变参数模板。我不是最擅长的,但想出了这个办法:
I was thinking about this, and like Jarod42 said, there must be some variadic template stuff. I'm not the best at this, but came up with this:
#include <memory>
#include <functional>
#include <iostream>
template <typename T, typename MemFn, typename... Params>
void safeExecute(T* ptr, MemFn memFn, Params&&... params) {
if (ptr != nullptr)
safeExecute(std::invoke(memFn, ptr), std::forward<Params>(params)...);
}
template <typename T, typename MemFn>
void safeExecute(T* ptr, MemFn memFn) {
if (ptr != nullptr) std::invoke(memFn, ptr);
}
struct Target {
void Bar() { std::cout << "tada!\n"; };
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() : ptr(std::make_unique<T>()) {}
T* Get() { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
safeExecute(myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get,
&Target::Bar);
}
编辑:
我一直在考虑使用更通用的返回类型,因此我尝试了不调用成员函数,而是返回指向对象的std :: optional指针的选项。这使我进入以下代码:
edit: I've been playing with the idea of having a more general return type, so I experimented with the option not to call the member function, but to return an std::optional pointer to the object. This lead me to the following code:
#include <memory>
#include <functional>
#include <iostream>
#include <optional>
template <typename T, typename MemFn, typename... Params>
auto safeGetObject(T* ptr, MemFn memFn, Params&&... params)
-> decltype(safeGetObject(std::invoke(memFn, std::declval<T>()), std::forward<Params>(params)...))
{
if (ptr != nullptr) return safeGetObject(std::invoke(memFn, ptr), std::forward<Params>(params)...);
return {};
}
template <typename T, typename MemFn>
auto safeGetObject(T* ptr, MemFn memFn) -> std::optional<decltype(std::invoke(memFn, std::declval<T>()))> {
if (ptr != nullptr) return std::invoke(memFn, ptr);
return {};
}
struct Target {
int Bar(int a, int b) const noexcept {
return a+b;
};
};
template<typename T>
class Object {
private:
std::unique_ptr<T> ptr;
public:
Object() noexcept : ptr(std::make_unique<T>()) {}
T* Get() const noexcept { return ptr.get(); }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
int main() {
auto myObjectPtr = std::make_unique<MyObject>();
auto optionalTarget = safeGetObject(
myObjectPtr.get(),
&MyObject::Get,
&SubObject::Get,
&SubSubObject::Get);
auto result = optionalTarget ? optionalTarget.value()->Bar(3, 4) : -1;
std::cout << " result " << result << '\n';
}
这篇关于有没有简单的方法来检查C ++中的不安全表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!