【发布时间】:2016-07-23 14:17:55
【问题描述】:
为什么T* operator->()即使写一次也会重复应用?但是另一个T& operator*()是申请一次,应该写多次。
众所周知,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) 中有什么关于这个的吗?
更新:
在不同的情况下,我们应该使用 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-> 应为不带参数的非静态成员函数。它实现了 使用 -> 的类成员访问语法。后缀表达式-> templateopt id-expression 后缀表达式 -> 伪析构函数名称 对于一个类,表达式 x->m 被解释为 (x.operator->())->m 如果 T::operator->() 存在并且操作符是 T 类型的对象 x 被重载决议选为最佳匹配函数 机制(13.3)。
即x->m 是 (x.operator->())->m。
【问题讨论】:
-
简短的回答是:因为这就是 C++ 的工作方式,因为这就是您编写的类的工作方式。
-
旁注:这是一个糟糕的问题,因为不必要地使用了“新”(没有与“删除”配对)
-
恕我直言,
operator->和operator*返回完全相同的类型,这本身就是不好的。
标签: c++ c++11 design-patterns dereference idioms