有没有一种简单的方法来检查C++中的不安全表达式
Is there a simple way to check unsafe expression in C++?
我正试图找到一种[更好]的方法来运行/检查一个潜在的不安全表达式,或者以更优雅的方式执行多个null检查。
以下是我想改进的代码示例:
if (myObjectPointer &&
myObjectPointer->getSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject() &&
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) {
// Use safely target
... *(myObjectPointer->getSubObject()->getSubSubObject()->getTarget()) ...
}
我试图找到一种更优雅的方法来实现这一点(而不是上面冗长的null检查(。以下是我的第一个想法:
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
}
...
上面的问题是我们无法捕捉信号(Segmentation fault,…(。我显然不想处理程序中的所有信号,只想处理这个非常特定的check/eval函数。
我是不是处理问题的方法不对?还有其他建议吗?还是冗长的if是不可避免的?
非常感谢。
我在想这个,就像Jarod42所说的,一定有一些可变模板的东西。我不是最擅长这方面的,但我想出了这个:
#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::可选指针。这让我想到了以下代码:
#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';
}
抛开可能的设计问题不谈,您可以使用std::optional
的扩展版本。由于不是所有的接口都在你的控制之下,你必须将必要的函数包装成一个自由函数。假设您可以更改myObjectPointer
的类MyClass
,但不能更改子对象的类。
class MyClass {
public:
optional<std::reference_wrapper<SubObjectClass>> getSubObject();
};
optional<std::reference_wrapper<SubSubObjectClass>> getSubSubObject(SubObjectClass& s) {
SubSubObjectClass* ptr = s.getSubSubObject();
if (ptr) {
return std::ref(s.getSubSubObject());
} else {
return {};
}
}
optional<std::reference_wrapper<Target>> getTarget(SubSubObjectCLass& s) {
...
}
你现在可以写类似的东西了
optional<MyClass*> myObjectPointer = ...;
myObjectPointer.and_then(MyClass::getSubObject)
.and_then(getSubSubObject)
.and_then(getTarget)
.map( doSomethingWithTarget ):
好吧,我可能会删除之前的答案,因为我一直在重新思考这个问题,现在考虑使用std::optional和chaining。您的原始
myObjectPointer->getSubObject()->getSubSubObject()->getTarget()
因为operator->()
不能是静态的。但是我们可以使用另一个运算符,比如operator>>()
。因此:
#include <memory>
#include <iostream>
#include <optional>
#include <functional>
struct Target {
int Bar(int a, int b) const noexcept { return a+b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
Object(T* ptr) noexcept : ptr(ptr) {}
T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template <typename T>
auto makeOptional(T* ptr) -> std::optional< std::reference_wrapper<T>> {
if (ptr) return std::ref(*ptr);
return {};
}
template <typename T, typename MemFn>
auto operator>> (std::optional<std::reference_wrapper<T>> optObj, MemFn memFn)
-> std::optional< std::reference_wrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>> {
if (optObj) return makeOptional(std::invoke(memFn, *optObj));
return {};
}
int main() {
{
//complete
auto TargetPtr = std::make_unique<Target>();
auto subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << 'n';
}
{
// incomplete
auto subObjectPtr = std::make_unique<SubObject>(nullptr);
auto myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto optionalMyObject = makeOptional(myObjectPtr.get());
auto optionalTarget = optionalMyObject >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto result = (optionalTarget) ? optionalTarget->get().Bar(3, 4) : -1;
std::cout << "result is " << result << 'n';
}
}
将工作。。。如果这是你想要的,请告诉我。
编辑:我还试着把它放在包装类中
#include <memory>
#include <iostream>
#include <functional>
#include <optional>
struct Target {
constexpr int Bar(int a, int b) const noexcept { return a + b; };
};
template<typename T>
class Object {
private:
T* const ptr;
public:
constexpr Object(T* const ptr) noexcept : ptr(ptr) {}
constexpr T* Get() const noexcept { return ptr; }
};
using SubSubObject = Object<Target>;
using SubObject = Object<SubSubObject>;
using MyObject = Object<SubObject>;
template<typename T>
class ObjectWrapper {
private:
std::optional<std::reference_wrapper<T>> optRefObj{};
public:
constexpr ObjectWrapper(T* ptr) noexcept
: optRefObj(ptr ? std::make_optional(std::ref(*ptr)) : std::nullopt)
{}
template<typename MemFn>
constexpr auto operator>>(MemFn memFn) const noexcept {
return ObjectWrapper<std::remove_pointer_t<decltype(std::invoke(memFn, std::declval<T>()))>>
(optRefObj ? std::invoke(memFn, *optRefObj) : nullptr);
}
constexpr operator bool() const noexcept { return optRefObj.has_value(); }
constexpr T* Get() noexcept { return optRefObj ? &optRefObj->get() : nullptr; }
};
int main() {
{
//complete
auto const TargetPtr = std::make_unique<Target>();
auto const subSubObjectPtr = std::make_unique<SubSubObject>(TargetPtr.get());
auto const subObjectPtr = std::make_unique<SubObject>(subSubObjectPtr.get());
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << 'n';
}
{
// incomplete
auto const subObjectPtr = std::make_unique<SubObject>(nullptr);
auto const myObjectPtr = std::make_unique<MyObject>(subObjectPtr.get());
auto const myObjWrp = ObjectWrapper(myObjectPtr.get());
auto optionalTarget = myObjWrp >> &MyObject::Get >> &SubObject::Get >> &SubSubObject::Get;
auto const result = optionalTarget ? optionalTarget.Get()->Bar(3, 4) : -1;
std::cout << "result is " << result << 'n';
}
}
相关文章:
- valgrind-hellgrind与泄漏检查的结果不同
- C++模板来检查友元函数的存在
- 检查输入是否不是整数或数字
- 试图让变量检查数组中的某些内容
- 检查值是否在集合p1和p2中,但不在p3中
- C++概念:如何使用'concept'检查模板化结构的属性?
- 概念TS检查忽略私有访问修饰符
- 检查 std::shared_ptr<> 的当前底层类型是否为 T
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- 如何在C++中检查2D数组中负值的输入验证
- C++:正在检查LinkedList中的回文-递归方法-错误
- 使用for循环检查数组中的重复项
- 如何检查一个c++字符串中有多少相同的字符/数字
- 检查不带转换的扫描格式
- 如何检查线程是否锁定
- 清除前检查矢量
- 如何处理来自核心指南检查器的关于gsl::at的静态分析警告
- C++LDAP检查用户是否是特定组的成员
- 检查TCHAR数组输入是否为带符号整数C++
- 用概念检查属性的类型