为什么即使写一次也会重复应用`T * operator->()`?

时间:2016-07-23 14:17:56

标签: c++ c++11 design-patterns dereference idioms

为什么即使写一次也会重复应用T* operator->()?但是另一个T& operator*()被应用一次,应该写多次。

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

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

  • lock mutex
  • 日志操作
  • 可视化更改数据

我在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)中有什么相关内容吗?

更新

在不同的情况下,我们应该使用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运营商 - &gt;应该是一个不带参数的非静态成员函数。它实现了   使用 - &gt;的类成员访问语法。 postfix-expression - &gt;   templateopt id-expression postfix-expression - &gt;伪析构函数名   表达式x-> m被解释为(x.operator-&gt;()) - &gt; m表示类   如果T :: operator-&gt;()存在且操作符是,则类型为T的对象x   通过重载决策选择最佳匹配函数   机制(13.3)。

即。 x->m(x.operator->())->m

2 个答案:

答案 0 :(得分:2)

当且仅当a->b是指针时,

(*a).b被定义为a

如果a不是指针,则将其定义为(a.operator->())->b。现在通常operator->返回一个指针,然后执行(*(a.operator->())).b并完成。

但如果它返回一个非指针,则该定义是递归的。

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

简而言之,标准就是如此。为什么?因为作家认为它既优雅又实用。

顺便说一句,operator.有一个活跃的提案,可能会在2021年使用C ++。这样就可以使(*a).b的行为与a->b相同。

答案 1 :(得分:1)

以下两个案例分解了一些:

(*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);

你需要用*取消引用两次的原因是因为proxy :: operator *()返回一个指向底层类型的指针。

如果有指针,可以直接使用“ - &gt;”调用其成员或者您可以用“*”取消引用它,然后使用“。”无论指针来自何处,都是如此。

由于你从*获得指针,并且你在该指针上使用*,这就是你使用两个*的原因。