shared_ptr不能为空



使用std::shared_ptr表示共享所有权和可选性(可能为空)。

发现自己的情况是,我只想在我的代码中表达共享所有权,而没有可选性。当使用shared_ptr作为函数参数时,我必须让函数检查它是否不为空以保持一致/安全。

在许多情况下,传递引用而不是当然是一种选择,但我有时也想转让所有权,因为可以通过shared_ptr

.

是否有一个类来替换shared_ptr而不可能为 null,有一些约定来处理这个问题,或者我的问题没有多大意义?

您要求not_null包装类。 幸运的是,您的问题已经通过专家指南解决了C++并且已经有示例实现 - 就像这个一样。搜索not_null类模板。

您可以围绕 std::shared_ptr 编写一个包装器,只允许从非 null 创建:

#include <memory>
#include <cassert>
template <typename T>
class shared_reference
{
    std::shared_ptr<T> m_ptr;
    shared_reference(T* value) :m_ptr(value) { assert(value != nullptr);  }
public:
    shared_reference(const shared_reference&) = default;
    shared_reference(shared_reference&&) = default;
    ~shared_reference() = default;
    T* operator->() { return m_ptr.get(); }
    const T* operator->() const { return m_ptr.get(); }
    T& operator*() { return *m_ptr.get(); }
    const T& operator*() const { return *m_ptr.get(); }
    template <typename XT, typename...XTypes>
    friend shared_reference<XT> make_shared_reference(XTypes&&...args);
};

template <typename T, typename...Types>
shared_reference<T> make_shared_reference(Types&&...args)
{
    return shared_reference<T>(new T(std::forward<Types>(args)...));
}

请注意,operator=尚未丢失。你绝对应该添加它。

你可以像这样使用它:

#include <iostream>

using std::cout;
using std::endl;
struct test
{
    int m_x;
    test(int x)         :m_x(x)                 { cout << "test("<<m_x<<")" << endl; }
    test(const test& t) :m_x(t.m_x)             { cout << "test(const test& " << m_x << ")" << endl; }
    test(test&& t)      :m_x(std::move(t.m_x))  { cout << "test(test&& " << m_x << ")" << endl; }
    test& operator=(int x)          { m_x = x;                  cout << "test::operator=(" << m_x << ")" << endl; return *this;}
    test& operator=(const test& t)  { m_x = t.m_x;              cout << "test::operator=(const test& " << m_x << ")" << endl; return *this;}
    test& operator=(test&& t)       { m_x = std::move(t.m_x);   cout << "test::operator=(test&& " << m_x << ")" << endl; return *this;}
    ~test()             { cout << "~test(" << m_x << ")" << endl; }
};
#include <string>
int main() {
    {
        auto ref = make_shared_reference<test>(1);
        auto ref2 = ref;
        *ref2 = test(5);
    }
    {
        test o(2);
        auto ref = make_shared_reference<test>(std::move(o));
    }
    //Invalid case
    //{
    //  test& a = *(test*)nullptr;
    //  auto ref = make_shared_reference<test>(a);
    //}
}

输出:

test(1)
test(5)
test::operator=(test&& 5)
~test(5)
~test(5)
test(2)
test(test&& 2)
~test(2)
~test(2)

科里鲁的例子

我希望我没有忘记任何可能导致未定义行为的事情。

看了一下 GSL 的 not_null 类,它调用 std::terminate() 而不是 abort() ;

以下是我实现它的方式:

template <typename T>
class NonNull : public std::shared_ptr<T> {
    typedef std::shared_ptr<T> super;
public:
    inline NonNull()
        : super(new T())
    {
        if ( ! super::get()) {
            abort(); // Out of memory.
        }
    }
    inline explicit NonNull(T *ptr)
        : super(ptr)
    {
        if ( ! super::get()) {
            abort(); // Input was null.
        }
    }
}

基本上,迫使我们构造T类型的类。

用法:

// Directly is a `std::shared_ptr` type:
NonNull<MyClass> myVariable;
// Unlike:
gsl::not_null<std::shared_ptr<MyClass > > myVariable;

相关内容

  • 没有找到相关文章

最新更新