2016-07-23 45 views
0

即使写入一次,为什么T* operator->()会重复应用?但另一个T& operator*()应用一次,并且应该写很多次。即使写入一次,为什么`T *运算符 - >()`被重复应用?

众所周知,C++中有Execute-Around Pointer Idiom。 More C++ Idioms/Execute-Around Pointer

提供一个智能指针对象,该对象在每个对象的每个函数调用之前和之后都透明地执行动作,前提是所执行的操作对所有函数都是相同的。并且对每一个治疗前后的成员变量进行一次处理。例如,我们可以执行:

  • 锁定互斥
  • 日志动作
  • 可视化改变数据

我加了一些在main()this example

#include <iostream> 
#include <vector> 

class VisualizableVector { 
    public: 
    class proxy { 
     public: 
     proxy (std::vector<int> *v) : vect (v) { 
      std::cout << "Before size is: " << vect->size() << std::endl; 
     } 
     std::vector<int> * operator ->() { return vect; } 
     std::vector<int> & operator *() { return *vect; } 
     ~proxy() { std::cout << "After size is: " << vect->size() << std::endl; } 
     private: 
     std::vector <int> * vect; 
    };   
    VisualizableVector (std::vector<int> *v) : vect(v) {}    
    ~VisualizableVector() { delete vect; } 
    proxy operator ->() { return proxy (vect); } 
    proxy operator *() { return proxy (vect); } 
    private: 
    std::vector <int> * vect; 
}; 

int main() 
{ 
    VisualizableVector vecc (new std::vector<int>); 

    vecc->push_back (10);   // 1. Note use of -> operator instead of . operator  
    vecc->push_back (20);   // 2. ok  
    (*vecc)->push_back (30);  // 3. ok  
    // (*vecc).push_back (40); // 4. error  
    (**vecc).push_back (50);  // 5. ok  
    // vecc->->push_back (60); // 6. error  
} 

在线编译结果: http://ideone.com/cXGdxW

为什么我们需要写两次**,但只有一次->

其经营者返回相同的事情proxy

proxy operator ->() { return proxy (vect); } 
    proxy operator *() { return proxy (vect); } 

,但为什么我们需要再次使用*,但我们不应该再次使用-> ?:

vecc->push_back (20);  // 2. ok  (vecc->) is proxy 
    (**vecc).push_back (50); // 5. ok  (*vecc) is proxy 

为什么不vecc->->push_back (20);

在标准C++(03/11/14)中有什么关于这个的吗?

UPDATE:

在不同情况下,我们应该使用1,2或3 operator-> S:http://ideone.com/89kfYF

#include <iostream> 
#include <vector>  
class VisualizableVector { 
    public: 
    class proxy { 
     public: 
     proxy (std::vector<int> *v) : vect (v) { 
      std::cout << "Before size is: " << vect->size() << std::endl; 
     } 
     std::vector<int> * operator ->() { return vect; } 
     std::vector<int> & operator *() { return *vect; } 
     ~proxy() { std::cout << "After size is: " << vect->size() << std::endl; } 
     private: 
     std::vector <int> * vect; 
    };   
    VisualizableVector (std::vector<int> *v) : vect(v) {}    
    ~VisualizableVector() { delete vect; } 
    proxy operator ->() { return proxy (vect); } 
    proxy operator *() { return proxy (vect); } 
    private: 
    std::vector <int> * vect; 
}; 

int main() 
{ 
    VisualizableVector vecc (new std::vector<int>); 

    vecc->push_back(30);   // ok  // one -> 
    //vecc.operator->().push_back(30);// error // one -> 

    //vecc->->push_back(30);   // error // two -> 
    vecc.operator->()->push_back(30); // ok  // two -> 

    auto proxy3 = vecc.operator->();  // 1st operator->() 
    auto pointer = proxy3.operator->(); // 2nd operator->() 
    pointer->push_back(30);    // 3rd operator->()  
    return 0; 
} 

页面327:Working Draft, Standard for Programming Language C++ 2014-11-19

13.5.6类的成员访问[over.ref] 1 operator->应该是一个不带参数的非静态成员函数。它实现了使用 - >的 类成员访问语法。 postfix-expression - > templateopt id-expression postfix-expression - > pseudo-destructor-name 表达式x-> m被解释为(x.operator - >()) - > m对于类 对象x的类型T如果T :: operator - >()存在,并且运算符 被过载分辨率 机制(13.3)选为最佳匹配函数。

I.e. x->m(x.operator->())->m

+0

简短的回答是:因为这就是C++的工作原理,因为这就是你编写类工作的方式。 –

+0

注意:这是一个不好的问题,因为不需要使用'new'(没有配对'delete') –

+0

恕我直言,'operator->'和'operator *'返回完全相同的类型,本身就不好。 –

回答

2

a->b定义为(*a).b当且仅当a是一个指针。如果a不是指针,则它被定义为(a.operator->())->b。现在通常operator->返回一个指针,所以它然后做一个(*(a.operator->())).b并完成。

但是,如果它反而返回一个非指针,这个定义是递归的。

没有类似的一元递归定义operator*

总之,标准是这样说的。为什么?因为作家认为它既优雅又有用。

顺便说一句,有一个积极的建议operator.可能会在2021年以C++。这将允许(*a).b行为与a->b相同。

+0

谢谢!即'x-> m'对于对象(不是指针)是相同的'(x.operator - >()) - > m',并且总是递归的。这在标准页面327中定义:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf – Alex

1

这里是那些2箱子有些细分:

(*vecc)->push_back(30);  // 3. ok  
VisualizableVector::proxy proxy3 = vecc.operator*(); 
std::vector<int> *pointer = proxy3.operator->(); 
pointer->push_back(30); 

(**vecc).push_back(50);  // 5. ok 
VisualizableVector::proxy proxy5 = vecc.operator*(); 
std::vector<int> &reference = proxy5.operator*(); 
reference.push_back(50); 

的原因,你需要与提领*两次是因为代理::运算符*()返回一个指针的基础类型。

当你有一个指针时,你可以用“ - >”直接调用它的成员,或者你可以用“*”对它进行解引用,然后使用“。”。无论指针来自何处,这仍然是真实的。

既然你得到了来自*的指针,并且你在该指针上使用了*,这就是为什么你使用了两个*。

+0

抱歉,我覆盖了某人的同时编辑,试图进行格式设置并使我的记谱保持一致。你能再次逃脱*吗,还是告诉我该怎么做? –

+0

谢谢。是的,我可以避免双'**'如果我实现投射运算符'代理::运营商std ::矢量&(){返回* vect; }'并使用隐式/显式'static_cast'。例如隐式的'std :: vector &vec_ref = * vecc;'或显式的'static_cast >(* vecc).push_back(40); // 4.a ok' http://ideone.com/IlvhPc – Alex