11

以下代码摘自:https ://github.com/facebook/folly/blob/master/folly/Synchronized.h

我最近看了 Folly 库,发现了一些有趣的东西。考虑以下示例:

#include <iostream>

struct Lock {
    void lock() {
        std::cout << "Locking" << std::endl;
    }
    void unlock() {
        std::cout << "Unlocking" << std::endl;
    }
};

template <class T, class Mutex = Lock >
struct Synchronized {
    struct LockedPtr {
        explicit LockedPtr(Synchronized* parent) : p(parent) {
            p->m.lock();
        }

        ~LockedPtr() {
            p->m.unlock();
        }

        T* operator->() {
            std::cout << "second" << std::endl;
            return &p->t;
        }

    private:
        Synchronized* p;
    };

    LockedPtr operator->() {
        std::cout << "first" << std::endl;
        return LockedPtr(this);
    }

private:
    T t;
    mutable Mutex m;
};

struct Foo {
    void a() {
        std::cout << "a" << std::endl;
    }
};

int main(int argc, const char *argv[])
{
    Synchronized<Foo> foo;
    foo->a();

    return 0;
}

输出是:

first
Locking
second
a
Unlocking

我的问题是:为什么这段代码有效?这种模式有名字吗?

-> 操作符被调用了两次,但它只写了一次。

4

2 回答 2

12

因为这就是标准所说的:

13.5.6 类成员访问 [over.ref]

1)operator->应该是一个不带参数的非静态成员函数。它使用一个表达式来实现类成员访问,如果 存在并且如果运算符被重载决策机制(13.3)选择为最佳匹配函数,则表达式被解释为类型的类对象。-> postfix-expression -> id-expression x->m(x.operator->())->mxTT::operator->()

(强调我的)

在您的情况下,xisfoomis a(),现在,Synchronized重载operator->foo->a()等效于:

(foo.operator->())->a();

foo.operator->()是你在类中的重载Synchronized,它返回一个LockedPtr,然后LockedPtr调用它自己的operator->

于 2012-09-11T08:17:07.073 回答
0

问问自己这个问题:它还能如何表现?

请记住,重载operator->的目的是让智能指针类可以使用与原始指针相同的语法。也就是说,如果您有:

struct S
{
    T m;
};

并且您有一个指向 的指针pS然后无论是 an类型还是某种类型,都可以S::m通过 via访问。p->mpS*pointer_class<S>

->直接使用和调用之间也有区别operator->

pointer_class<S> pointerObj;
S* p = pointerObj.operator->();

请注意,如果使用重载->不会自动降低额外级别,那p->m可能意味着什么?怎么可能使用过载?

于 2012-09-11T08:33:34.390 回答