标准容器封装和基于范围的 for 循环
Standard containers encapsulation and range-based for loops
我正在设计一个有两个标准向量作为成员的类。我希望能够在矢量元素上使用基于范围的 for 循环,我想出了这个解决方案
#include <iostream>
#include <vector>
using namespace std;
class MyClass {
public:
void addValue1(int val){data1_.push_back(val);}
void addValue2(int val){data2_.push_back(val);}
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
// ...
private:
vector<int> data1_;
vector<int> data2_;
// ...
};
void print1(MyClass const & mc) {
for (auto val : mc.data1()){
cout << val << endl;
}
}
void print2(MyClass const & mc) {
for (auto val : mc.data2()){
cout << val << endl;
}
}
int main(){
MyClass mc;
mc.addValue1(1);
mc.addValue1(2);
mc.addValue1(3);
print1(mc);
}
显然,定义begin()
和end()
函数的替代方案没有意义,因为我有两个不同的向量。
我想问以下问题:
所提出的解决方案的一个缺点是两个向量的内容无法更改(由于
const
限定符)。如果我需要修改矢量元素,如何修改代码?编辑:修改应保留封装考虑到数据封装,你认为返回对两个向量的(
const
)引用是一种不好的做法吗?
使用类似gsl::span<int>
和gsl::span<const int>
的东西。
这是一个最小的:
template<class T>
struct span {
T* b = 0; T* e = 0;
T* begin() const { return b; }
T* end() const { return e; }
span( T* s, T* f ):b(s),e(f) {}
span( T* s, std::size_t len ):span(s, s+len) {}
template<std::size_t N>
span( T(&arr)[N] ):span(arr, N) {}
// todo: ctor from containers with .data() and .size()
// useful helpers:
std::size_t size() const { return end()-begin(); }
bool empty() const { return size()==0; }
T& operator[](std::size_t i) const { return begin()[i]; }
T& front() const { return *begin(); }
T& back() const { return *(std::prev(end())); }
// I like explicit defaults of these:
span() = default;
span(span const&) = default;
span& operator=(span const&) = default;
~span() = default;
};
现在你可以写:
span<int const> data1() const {return {data1_.data(), data1_.size()};}
span<int const> data2() const {data2_.data(), data2_.size()};}
span<int> data1() {return {data1_.data(), data1_.size()};}
span<int> data2() {data2_.data(), data2_.size()};}
所提出的解决方案的一个缺点是两个向量的内容无法更改(由于常量限定符)。如果我需要修改矢量元素,如何修改代码?
首先,您应该添加一个data1()
和一个data2()
non-const 版本,这些版本返回对data1_
和data2_
成员的引用
vector<int> const & data1() const {return data1_;}
vector<int> const & data2() const {return data2_;}
vector<int> & data1() {return data1_;}
vector<int> & data2() {return data2_;}
第二:如果你想修改元素print1()
(通过示例),你必须接收mc
作为 not const 引用
// ..........vvvvvvvvv no more const
void print1 (MyClass & mc) {
所以你可以改变mc
.
第三:在基于范围的循环中,您必须将val
定义为参考,以便您可以修改它,同时修改向量内的引用值
// ........V by reference
for ( auto & val : mc.data1() ) {
++val ; // this modify the value in the vector inside mc
cout << val << endl;
}
考虑到数据封装,您认为返回对两个向量的(const)引用是一种不好的做法吗?
恕我直言:如果引用是const
,则根本不是:这是一个很好的做法,因为允许安全使用成员而无需复制它。
如果引用不是const
,我认为与声明成员公共没有太大区别。
相关文章:
- 基于范围循环到旧编译器的旧样式
- 带有自定义对象的C 范围循环
- 为什么编译器不优化集合元素上的空范围循环?
- 迭代在包含向量的vor in for for范围循环中迭代
- 我们可以在范围循环中使用引用(而不是指针)上的删除
- 如何实现我的自定义范围循环
- C++范围循环
- GCC 4.4 不实现 C++11 范围循环.它还支持哪些其他范围循环语法
- 嵌套c++11范围循环,用于查找组合
- 范围循环中的访问索引
- 对于不可复制类型的范围循环,是否可能
- 我的范围循环出现逻辑错误
- 如何在我的类上允许范围循环
- c++的范围循环比递减循环快
- 通过范围循环从指针容器中获取取消引用元素的引用
- c++ 11:为什么这个范围循环会使FPS下降35
- 带有自定义类的范围循环(矢量的简单版本<string>,使用分配器)
- MSVC10 Visual Studio 2010支持c++范围循环吗?
- 围绕 2 的幂范围循环变量
- toupper() 在 for 范围循环中不起作用