C++ 数组订阅:返回引用与代理类方法
在搜索为模板类重载下标(“[]”)运算符的方法时,我遇到了两种不同的技术 第一个技巧: 重载C++ 数组订阅:返回引用与代理类方法,c++,operator-overloading,subscript-operator,C++,Operator Overloading,Subscript Operator,在搜索为模板类重载下标(“[]”)运算符的方法时,我遇到了两种不同的技术 第一个技巧: 重载操作符[]直接返回指向容器的指针,这将允许读取值和赋值。此技术的示例实现: template <class T> class X { int _size; T *container; public: X(int sz) { _size=sz; container=new T[sz](); } ~X() {
操作符[]
直接返回指向容器的指针,这将允许读取值和赋值。此技术的示例实现:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
T& operator [](int indx)
{
return container[indx];
}
};
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
class Proxy
{
int indx;
X<T> &parent;
public:
Proxy(X<T> &p, int x) : parent(p),indx(x)
{
}
void operator =(T assgn)
{
parent.container[indx]=assgn;
}
operator T const &()
{
return parent.container[indx];
}
friend class X<T>;//unnecessary line, I know!
};
Proxy operator[](int indx)
{
return Proxy(*this,indx);
}
};
输出:
0
9
第二种技巧:
第二种技术涉及声明一个代理类并通过该类重载操作符=
。此技术的示例实现:
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
T& operator [](int indx)
{
return container[indx];
}
};
template <class T>
class X
{
int _size;
T *container;
public:
X(int sz)
{
_size=sz;
container=new T[sz]();
}
~X()
{
}
class Proxy
{
int indx;
X<T> &parent;
public:
Proxy(X<T> &p, int x) : parent(p),indx(x)
{
}
void operator =(T assgn)
{
parent.container[indx]=assgn;
}
operator T const &()
{
return parent.container[indx];
}
friend class X<T>;//unnecessary line, I know!
};
Proxy operator[](int indx)
{
return Proxy(*this,indx);
}
};
模板
X类
{
内部尺寸;
T*集装箱;
公众:
X(内部深圳)
{
_尺寸=sz;
容器=新的T[sz]();
}
~X()
{
}
类代理
{
int indx;
X&parent;
公众:
代理(X&p,int X):母公司(p),indx(X)
{
}
void运算符=(T assgn)
{
parent.container[indx]=assgn;
}
运算符T常量&()
{
返回父容器[indx];
}
朋友X类;//不必要的线,我知道!
};
代理运算符[](int indx)
{
返回代理(*此,indx);
}
};
使用相同的main()
我们得到相同的输出
我个人喜欢第二种方法。但是,我真的想比较这两种方法。这两种技术的主要功能区别是什么。这些方法各有哪些优点?如果您希望公开一系列未按原样存储(需要从存储转换为存储)或无法通过引用访问的元素,则可以使用您描述的基于代理的技术。例如std::vector
如果您可以返回对存储对象的直接引用,那么将其包装在代理中没有真正的好处,除非您希望限制赋值(例如,仅允许容器中的正值)。通常,当您希望返回与数据的内部存储不匹配的内容时,会使用代理。典型的例子是二维矩阵,元素存储在单个数组中。如果提供了返回行或列的运算符,则需要代理。另一个例子是臭名昭著的
std::vector
,其中数据不需要存储为bool
块,但访问必须将bool
返回给用户
代理可用于返回内部数据表示的段的不同“视图”。在您的示例中,似乎没有理由使用它们。为大多数客户端使用正确的代理对象要复杂得多。。。例如,如果有人说:
tcp_peer.send_from_iterator_range(&sample[2], &sample[7+1]);
如果sample::operator[]
返回一个临时代理,并且该代理没有仔细地替换operator&
,那么代码会询问代理本身的地址
在不失去代理拦截对数据的读取和/或写入的能力的情况下,某些客户端使用就无法得到支持,例如在
Container::element_type& ref = container[n];
ref = 20;
…客户端代码假定容器的操作符[]
将生成对实际元素的引用。运算符[]
返回的任何代理必须提供一个运算符元素类型&(
)-移交这样的引用并使其自身不起作用-或拒绝(例如,仅返回常量
引用,返回非常量
引用无法绑定的临时by值)并强制编辑客户端代码
因此,当您需要代理时,代理的性能可以达到95%,但当您不需要代理时,最好避免使用代理。这里是第一种技术和第二种技术(代理
技术)之间的另一个区别。使用auto-element=createX()[3]时//createX返回一个X
来检索X中的元素(X是一个临时对象),第一种技术为您提供一个T
,它是3
rd元素的副本。而代理
将为您提供一个代理
类型的元素
,它实际上是指一个临时X对象。因此,由于挂起代理而导致未定义的行为。