为什么`T* operator->()` 即使写了一次也会重复应用?
Why the `T* operator->()` is applied repeatedly even if written once?
为什么T* operator->()
写了一次就重复应用了?但是另一个T& operator*()
应用一次,应该写很多次。
众所周知,C++ 中有 Execute-Around Pointer Idiom。 More C++ Idioms/Execute-Around Pointer
提供一个智能指针对象,它在对象的每个函数调用之前和之后透明地执行操作,前提是所有函数执行的操作都是相同的。并且每次处理前后都给一个class的成员变量。例如我们可以执行:
- 锁定互斥体
- 记录操作
- 可视化变化的数据
我在 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
为什么我们需要写两次**
,而只写一次->
?
它的运算符return一样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 Class member access [over.ref] 1 operator-> shall be a non-static member function taking no parameters. It implements the
class member access syntax that uses ->. postfix-expression ->
templateopt id-expression postfix-expression -> pseudo-destructor-name
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).
即x->m
是 (x.operator->())->m
.
以下是这两个案例的细分:
(*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 * () returns 指向基础类型的指针。
当你有一个指针时,你可以直接用“->”调用它的成员,或者你可以用“*”取消引用它然后使用“。”无论指针来自何处,这都是正确的。
因为你从 * 得到了指针,并且你在那个指针上使用了 *,所以你使用了两个 *。
a->b
被定义为 (*a).b
当且仅当 a
是一个指针。
如果a
不是指针,则定义为(a.operator->())->b
。现在通常 operator->
returns 一个指针,因此它会执行 (*(a.operator->())).b
并完成。
但如果它 returns 是一个非指针,则此定义是递归的。
没有类似的一元递归定义operator*
。
简而言之,标准是这么说的。为什么?因为作者认为它既优雅又实用。
顺便说一句,有一个针对 operator.
的活跃提案,到 2021 年可能会在 C++ 中出现。这将允许 (*a).b
的行为与 a->b
相同。
为什么T* operator->()
写了一次就重复应用了?但是另一个T& operator*()
应用一次,应该写很多次。
众所周知,C++ 中有 Execute-Around Pointer Idiom。 More C++ Idioms/Execute-Around Pointer
提供一个智能指针对象,它在对象的每个函数调用之前和之后透明地执行操作,前提是所有函数执行的操作都是相同的。并且每次处理前后都给一个class的成员变量。例如我们可以执行:
- 锁定互斥体
- 记录操作
- 可视化变化的数据
我在 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
为什么我们需要写两次**
,而只写一次->
?
它的运算符return一样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 Class member access [over.ref] 1 operator-> shall be a non-static member function taking no parameters. It implements the class member access syntax that uses ->. postfix-expression -> templateopt id-expression postfix-expression -> pseudo-destructor-name 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).
即x->m
是 (x.operator->())->m
.
以下是这两个案例的细分:
(*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 * () returns 指向基础类型的指针。
当你有一个指针时,你可以直接用“->”调用它的成员,或者你可以用“*”取消引用它然后使用“。”无论指针来自何处,这都是正确的。
因为你从 * 得到了指针,并且你在那个指针上使用了 *,所以你使用了两个 *。
a->b
被定义为 (*a).b
当且仅当 a
是一个指针。
如果a
不是指针,则定义为(a.operator->())->b
。现在通常 operator->
returns 一个指针,因此它会执行 (*(a.operator->())).b
并完成。
但如果它 returns 是一个非指针,则此定义是递归的。
没有类似的一元递归定义operator*
。
简而言之,标准是这么说的。为什么?因为作者认为它既优雅又实用。
顺便说一句,有一个针对 operator.
的活跃提案,到 2021 年可能会在 C++ 中出现。这将允许 (*a).b
的行为与 a->b
相同。