我想编写安全的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 ++中已经没有东西了吗?还是可以轻松实现?
答案 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_ptr
将operator 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>>
。