std :: optional <std :: shared_ptr <MyClass >>是否有助于避免空值引用?

时间:2020-09-15 09:00:15

标签: c++

我想编写安全的C ++程序,因此:

我想避免内存泄漏,所以我开始使用std::shared_ptr

但是,有些时候我仍然有一些空指针引用。我想到了使用using MyClassSafe = std::optional<std::shared_ptr<MyClass>>的想法。

然后,我避免了内存泄漏和空指针引用。好吧,有点。例如:

MyClassSafe myClassSafe = std::make_shared<MyClass>();
//Then everytime I want to use myClassSafe:
if (myClassSafe) {
    //use it here
} else {
    //do something in case no value
}

//However, this situation can be possible:
MyClassSafe notVerySafe = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClassSafe) {
    //use it here, for example:
    //this deferences a nullptr
    myClassSafe.value()->someFunction();
} else {
    //do something in case no value
}

所以这并不安全。更好,但我仍然会犯错误。

我可以想象一个safe_shared_ptr<T>类,它可以返回operator->(很像Rust),而不是在std::optional<T&>上调用对象的函数,然后我们可以安全地对其进行调用或处理std::nullopt情况。 C ++中已经没有东西了吗?还是可以轻松实现?

4 个答案:

答案 0 :(得分:1)

optional<T>允许您处理shared_ptr<T>已处理的“无可用”情况。因此optional<shared_ptr<T>>是多余的,就像optional<optional<T>>一样。

shared_ptr<optional<T>>有一种情况-如果一个所有者创建了T对象,另一所有者可以看到新对象,因此这并不是多余的。

答案 1 :(得分:1)

这里没有显示 指针或可选参数的需要。

MyClass myClassSafe;
myClassSafe.someFunction();

看不到空指针或空的可选内容的可能性。

答案 2 :(得分:0)

您在这里使用std::optional是导致问题的原因。 std::shared_ptroperator bool定义为空指针检查,但是由于您已经将其包装在std::optional中,因此永远不会被调用

如果相反,您尝试:

MyClass myClass = std::make_shared<MyClass>(nullptr); // or = std::shared_ptr(nullptr);
if (myClass) {
    // std::shared_ptr implements operator bool as a null pointer check
    myClass->someFunction();
} else {
    //do something in case no value
}

答案 3 :(得分:0)

C ++中已经没有东西了吗?

std中没有任何东西可以处理非null智能指针。

正如Caleth在他的答案中所示,您可以直接使用对象,并避免使用(智能)指针和std::optional

还是可以轻松实现?

非null智能指针(“智能引用” :))应默认为不可构造,而“不可移动”(我的意思是移动不应使引用无效)。

您可以使用现有的智能指针来实现它,例如:

template <typename T>
class unique_ref
{
public:
    // Avoid variadic constructor which might take precedence over regular copy/move constructor
    // so I use tag std::in_place_t here.
    template <typename ... Ts>
    unique_ref(std::in_place_t, Ts&&... args) : std::make_unique<T>(std::forward<Ts>(args)...) {}

    unique_ref(const unique_ref&) = delete;
    unique_ref(unique_ref&&) = delete;

    unique_ref& operator=(const unique_ref&) = delete;
    unique_ref& operator=(unique_ref&&) = delete;

    const T& operator*() const { return *ptr; }
    T& operator*() { return *ptr; }

    const T* operator ->() const { return ptr.get(); }
    T* operator*() { return ptr.get(); }

private:
    std::unique_ptr<T> ptr;
};

template <typename T, typename ... Ts>
unique_ref<T> make_unique_ref(Ts&&... args)
{
    return {std::in_place, std::forward<Ts>(args)...};
}

唯一版本不是很有用,因为它是不可复制,不可移动的。直接使用T似乎更简单。

共享版本是可复制的(其移动应与复制相同) 弱版本可能返回std::optional<shared_ref<T>>

相关问题