如何为 class unique_ptr 创建运算符->

How to create an operator-> for a class unique_ptr

我必须实现一个简单的“unique_ptr”class,仅支持构造函数、析构函数、–>、* 和 release()。我在下面做了。

不过写成“up.operator->()”来获取指针p,感觉怪怪的。我写“up->p”会更合乎逻辑。但是我该怎么做呢?谢谢!

#include <iostream>
#include <stdexcept>

template <class T>
class unique_ptr
{
    T *p;

public:        
    unique_ptr(T *ptr)
        : p{ptr}
    {
    }
    ~unique_ptr() { delete p; }


    T *operator->() const { return p; } // returns a pointer
    T operator*() const { return *p; }
    T *release()
    {
        T *ptr = p;
        p = nullptr;
        return ptr;
    }
};

template <class T>
void print(const unique_ptr<T> &up, const std::string &s)
{
    std::cout << s << " up.operator->(): " << up.operator->() << '\n';
    std::cout << s << " up.operator*(): " << up.operator*() << '\n'; 
}

int main()
try
{
    int *ptr = new int(10);

    unique_ptr<int> up(ptr);
    print(up, "up: ");

}

catch (std::exception &e)
{
    std::cerr << "exception: " << e.what() << '\n';
    return 1;
}
catch (...)
{
    std::cerr << "exception\n";
    return 2;
}

However, it feels weird to write "up.operator->()" to get the pointer p.

感觉很奇怪,因为成员访问运算符通常不用于获取指向对象的指针(尽管您可以使用 operator->() 语法来实现,如您所演示的)。成员访问运算符用于访问对象的成员。在您的示例中,您有一个唯一的指针 intint 没有成员,因此使用成员访问运算符没有意义。

这是一个如何使用它的例子:

struct S {
    int member;
};

unique_ptr<S> up(new S{10});
int value_of_member = up->member;

would be more logical to write "up->p"

这不合逻辑,除非 p 是指向对象的成员。

How to create an operator-> for a class unique_ptr

就像您在示例中所做的那样。据我所知,如何创建运算符没有问题,问题在于如何使用它。


P.S。您的唯一指针是可复制的、可移动的和可分配的,但这些操作被严重破坏导致未定义的行为。参见规则 5。

正如其他人在评论中指出的那样,这种单一所有权智能指针的实现是不完整的,operator*() 是不正确的,因为它不是 return 引用,因此不利于进行分配通过指针。

但是要回答这个问题,

it feels weird to write "up.operator->()" to get the pointer p. I would be more logical to write "up->p". But how do I do that?

好吧,你不想这样做,因为 p 是你的智能指针 class 私有实现的一部分。写 up.operator->() 很奇怪,因为那不是 -> 通常的用法。它通常用作 shorthand 来访问结构的成员,或者 class 比 * 运算符与通过 . 的成员访问相结合,稍微不那么冗长。要以一种不那么奇怪的方式使用你的指针,你需要用一些具有字段的类型来实例化模板参数,例如

struct foo {
    int bar;
};

void print(const unique_ptr<foo>& up, const std::string& s)
{
    std::cout << s << " up.operator->(): " << up->bar << '\n';
    std::cout << s << " up.operator*(): " << (*up).bar << '\n';
}

int main()
{
    unique_ptr<foo> up(new foo{ 42 });
    print(up, "up: ");

}