有没有办法阻止将“new T”传递给我的 observer_ptr 构造函数?

问题描述 投票:0回答:3

我想实现我自己的

observer_ptr
类,我想用它来表示没有指针的所有权。我想知道是否有可能以某种方式阻止某人使用以下语法:

observer_ptr<T> var_name(new T);

因为它会完全破坏这个类的全部目的并导致内存泄漏。我的猜测是我必须删除/私有化某种类型的构造函数,但我不知道我应该选择哪种参数类型来实现它。

我没有写任何可共享的库,我对自己提出更多要求,以便我可以学习。

c++ pointers new-operator
3个回答
2
投票

如果您通过非常量引用接受输入

T*
指针,用户不能在构造函数调用中直接调用
new
,因为引用将无法绑定到
new
返回的临时值,例如:

template <typename T>
class observer_ptr
{
public:
    observer_ptr(T*& ptr);
    ...
};
observer_ptr<T> var_name(new T); // error!

他们将需要使用本地

T*
变量来代替,使他们更加意识到自己对所创建对象的生命周期负有责任,例如:

T *ptr = new T;
observer_ptr<T> var_name(ptr); // OK!

但是请注意,这种方法确实会阻止用户直接观察地址被

operator&
std::addressof()
获取的非动态对象,以及
unique_ptr
shared_ptr
对象,例如:

T obj;
observer_ptr<T> var_name(&obj); // error!
auto ptr = make_unique<T>(); // or make_shared()
observer_ptr<T> var_name(ptr.get()); // error!

这也需要使用本地

T*
指针,例如:

T obj;
T* ptr = &obj;
observer_ptr<T> var_name(ptr); // OK!
auto obj = make_unique<T>(); // or make_shared()
T* ptr = obj.get();
observer_ptr<T> var_name(ptr); // OK!

你可以避免,如果你添加一些额外的构造函数到

observer_ptr
,例如:

template <typename T>
class observer_ptr
{
private:
    T* m_ptr;
public:
    observer_ptr(T*& ptr) : m_ptr(ptr) {}
    observer_ptr(T& obj) : m_ptr(addressof(obj)) {}
    observer_ptr(const unique_ptr<T>& ptr) : m_ptr(ptr.get()) {}
    observer_ptr(const shared_ptr<T>& ptr) : m_ptr(ptr.get()) {}
    observer_ptr(unique_ptr<T>&&) = delete;
    observer_ptr(shared_ptr<T>&&) = delete;
    ...
};
T obj;
observer_ptr<T> var_name(obj); // OK!
auto ptr = make_unique<T>(); // or make_shared()
observer_ptr<T> var_name(ptr); // OK!
observer_ptr<T> var_name(make_unique<T>()); // error!
observer_ptr<T> var_name(make_shared<T>()); // error!

1
投票

不可能对构造函数参数做这样的限制。如果你拿一个指针,它可以是任何指针(兼容类型)。

然而在我看来,这不是你应该用语言强制执行的东西,而是一个契约和类的意图,因为如果你看看智能指针类,它们也接受任何指针类型,并且在它出现时完全依赖文档和常识他们采用什么样的指针:

int stackValue;
std::unique_ptr myPtr{ &stackValue }; // it will be UB upon myPtr destruction but compiles anyway

此外,原始指针

T*
是表达对象不拥有的某些指针的常规方式。所以你可能在这里重新发明轮子并且可能想要重新考虑这个意图。


0
投票

不管怎样,你都需要能够传递一个(智能)指针或一个引用来创建一个

observer_ptr
,而用户总是能够把它搞砸。您可以通过更明显的方式让标题状态的用户了解他们打算做什么,并希望让他们充分考虑他们正在编写的代码以自己捕获错误。

您可以通过添加一个函数来创建

observer_ptr
并通过可见性限制要求使用它来完成此操作。以下示例要求用户使用
make_unowned_ptr(...)
为空指针以外的任何内容创建
observer_ptr

template<class T>
class observer_ptr;

template<class T>
constexpr observer_ptr<T> make_unowned_ptr(T* ptr)
{
    return { ptr };
}

template<class T>
class observer_ptr
{
    T* m_ptr;

    constexpr observer_ptr(T* ptr)
        : m_ptr(ptr)
    {
    }

    friend constexpr observer_ptr<T> make_unowned_ptr<T>(T*);
public:
    constexpr observer_ptr(std::nullptr_t = nullptr)
        : m_ptr(nullptr)
    {
    }
};

int main()
{
    int value = 1;
    observer_ptr<int> ptr1(&value); // compiler error: constructor not visible
    auto ptr2 = make_unowned_ptr(&value); // ok
}
© www.soinside.com 2019 - 2024. All rights reserved.