简体   繁体   English

为什么编译器会两次调用 - >运算符

[英]Why does the compiler invoke the -> operator twice

The following code is extracted from: https://github.com/facebook/folly/blob/master/folly/Synchronized.h 以下代码摘自: https//github.com/facebook/folly/blob/master/folly/Synchronized.h

I recent had a look at the Folly library, and found something interesting. 我最近看了一下Folly库,发现了一些有趣的东西。 Consider the following example: 请考虑以下示例:

#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;
}

The output is: 输出是:

first
Locking
second
a
Unlocking

My question is: Why is this code valid? 我的问题是:为什么这段代码有效? Does this pattern have a name? 这个模式有名字吗?

The -> operator is called twice, but it has only been written once. - >运算符被调用两次,但它只写了一次。

Because that's what the standard says: 因为这就是标准所说的:

13.5.6 Class member access [over.ref] 13.5.6类成员访问[over.ref]

1) operator-> shall be a non-static member function taking no parameters. 1) operator->应该是一个不带参数的非静态成员函数。 It implements class member access using -> postfix-expression -> id-expression An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism (13.3). 它使用-> postfix-expression -> id-expression实现类成员访问如果T::operator->()表达式x->m被解释为(x.operator->())->m表示类型为T的类对象x T::operator->()存在,如果操作符被重载决策机制选为最佳匹配函数(13.3)。

(emphasis mine) (强调我的)

In your case, x is foo and m is a() , Now, Synchronized overloads operator-> , foo->a() is equivalent to: 在你的情况下, xfooma() ,现在, Synchronized重载operator->foo->a()相当于:

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

foo.operator->() is your overload in class Synchronized , which returns a LockedPtr , and then that LockedPtr calls its own operator-> . foo.operator->()是您在Synchronized类中的重载,它返回一个LockedPtr ,然后LockedPtr调用它自己的operator->

Ask yourself this: how else could it possibly behave? 问问自己:它可能还有什么其他表现?

Remember, the point of overloading operator-> at all is so that a smart pointer class can use the same syntax as a raw pointer. 请记住,重载operator->的重点是智能指针类可以使用与原始指针相同的语法。 That is, if you have: 也就是说,如果你有:

struct S
{
    T m;
};

and you have a pointer p to S , then you access S::m via p->m regardless of whether p is an S* or some pointer_class<S> type. 并且你有一个指针pS ,然后通过p->m访问S::m ,无论pS*还是某个pointer_class<S>类型。

There's also the difference between using -> and invoking operator-> directly: 使用->和直接调用operator->之间也有区别:

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

Note that if using an overloaded -> didn't automatically descend the extra level, what would p->m ever possibly mean? 请注意,如果使用重载->没有自动降低额外级别,那么p->m可能意味着什么? How could the overload ever be used? 如何使用过载?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么deque :: erase()会调用赋值运算符? - Why does deque::erase() invoke assignment operator? 为什么 std::tuple 调用运算符 &lt;=&gt; 两次? - Why does std::tuple call operator <=> twice? 为什么map.insert()方法会两次调用复制构造函数? - Why does the map.insert() method invoke the copy constructor twice? 为什么编译器在分配时调用模板化副本构造函数? - Why does the compiler invoke a templated copy constructor when assigning? 为什么与<运算符的矢量比较比较每个项目两次? - Why does vector comparison with < operator compare each item twice? 使用operator >>两次后为什么std :: getline失败? - why does std::getline fails after using operator>> twice? 为什么编译器不会在以加法运算符开头的行中停止? - Why does compiler not balk at a line beginning with an addition operator? 为什么我的编译器在它有 2 个参数时坚持 operator&lt;&lt; 有 3 个参数? - Why does my compiler insist that operator<< has 3 parameters when it has 2? 为什么编译器报告“operator&lt;&lt; and operator&gt;&gt; recursive on all control path will cause stack overflow”? - Why does the compiler report "operator<< and operator>> recursive on all control paths will cause stack overflow "? 编译器是否提供地址运算符? - Does the compiler provide a address operator?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM