【发布时间】:2017-11-29 05:19:23
【问题描述】:
我正在实现一个二维数组容器(如boost::multi_array<T,2>,主要用于练习)。为了使用双索引表示法(a[i][j]),我引入了一个代理类row_view(和const_row_view,但我不关心这里的常量),它保留了指向行开头和结尾的指针。
我还希望能够分别迭代行和行中的元素:
matrix<double> m;
// fill m
for (row_view row : m) {
for (double& elem : row) {
// do something with elem
}
}
现在,matrix<T>::iterator 类(用于迭代行)在内部保留了一个私有 row_view rv;,以跟踪迭代器指向的行。当然,iterator 也实现了解引用功能:
- 对于
operator*(),通常希望返回一个引用。相反,这里正确的做法似乎是按值返回row_view(即返回私有row_view的副本)。这确保了当迭代器前进时,row_view仍然指向前一行。 (在某种程度上,row_view的行为类似于引用)。 -
对于
operator->(),我不太确定。我看到两个选项:-
返回指向迭代器私有
row_view的指针:row_view* operator->() const { return &rv; } -
返回指向新
row_view的指针(私有的副本)。由于存储寿命,必须在堆上分配。为了确保清理,我将其包装在unique_ptr:std::unique_ptr<row_view> operator->() const { return std::unique_ptr<row_view>(new row_view(rv)); }
-
显然,2 更正确。如果迭代器在调用 operator-> 之后 是高级的,则 1 中指向的 row_view 将发生变化。但是,我能想到的唯一方法是,operator-> 是否按其全名调用并且返回的指针已绑定:
matrix<double>::iterator it = m.begin();
row_view* row_ptr = it.operator->();
// row_ptr points to view to first row
++it;
// in version 1: row_ptr points to second row (unintended)
// in version 2: row_ptr still points to first row (intended)
但是,这不是您通常使用operator-> 的方式。在这种用例中,您可能会调用operator* 并保留对第一行的引用。通常,人们会立即使用指针来调用row_view 的成员函数或访问成员,例如it->sum().
我现在的问题是:鉴于-> 语法建议立即使用,operator-> 返回的指针的有效性是否被认为仅限于这种情况,或者 安全上述“滥用”的实施原因?
显然,解决方案 2 更昂贵,因为它需要堆分配。这当然是非常不可取的,因为取消引用是一项非常常见的任务,并且没有真正需要它:使用operator* 可以避免这些问题,因为它返回了row_view 的堆栈分配副本。
【问题讨论】:
-
我很确定你必须返回
operator *的引用和operator ->的指针:stackoverflow.com/questions/37191290/… -
根据cppreference:“运算符 -> 的重载必须返回一个原始指针或返回一个对象(通过引用或按值),而运算符 -> 反过来又被重载。”
-
至于
operator*,我没有发现任何限制。编译器肯定不会抱怨。 -
它不会抱怨,但标准的期望是获取对容器包含的元素的引用。
-
我认为
row_view有点像“智能参考”。我同意应该滥用运算符重载违背用户的期望,但在这种情况下,它似乎满足了用户的期望
标签: c++ iterator containers unique-ptr