简体   繁体   English

标准容器封装和基于范围的for循环

[英]Standard containers encapsulation and range-based for loops

I'm designing a class which has two standard vectors as members. 我正在设计一个类,该类具有两个标准向量作为成员。 I would like to be able to use range-based for loops on the vector elements and I came up with this solution 我希望能够在向量元素上使用基于范围的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);
}

Clearly, the alternative of defining begin() and end() functions doesn't make sense since I have two distinct vectors. 显然,因为我有两个不同的向量,所以定义begin()end()函数的选择没有意义。

I would like to ask the following questions: 我想问以下问题:

  • A shortcoming of the proposed solution is that the contents of the two vectors cannot be changed (due to the const qualifier). 所提出的解决方案的缺点是两个向量的内容不能更改(由于const限定符)。 In the case I need to modify the vector elements how can I modify the code? 在需要修改向量元素的情况下,如何修改代码? EDIT: the modification should preserve encapsulation 编辑:修改应保留封装

  • Considering data encapsulation, do you think it is bad practice to return a ( const ) reference to the two vectors? 考虑到数据封装,您是否认为对两个向量返回( const )引用是不好的做法?

Use something like gsl::span<int> and gsl::span<const int> . 使用gsl::span<int>gsl::span<const int>

Here is a minimal one: 这是最小的一个:

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;
};

now you can write: 现在您可以写:

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()};}

A shortcoming of the proposed solution is that the contents of the two vectors cannot be changed (due to the const qualifier). 所提出的解决方案的缺点是两个向量的内容不能更改(由于const限定符)。 In the case I need to modify the vector elements how can I modify the code? 在需要修改向量元素的情况下,如何修改代码?

First of all, you should add a data1() and a data2() not-const versions that return a reference to the data1_ and data2_ members 首先,您应该添加一个data1()data2()非常量版本,这些版本返回对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_;}

Second: if you want modify the element in print1() (by example) you have to receive mc as not const reference 第二:如果要修改print1()的元素(例如),您必须将mc作为非const引用接收

// ..........vvvvvvvvv   no more const
void print1 (MyClass & mc) {

so you can change mc . 因此您可以更改mc

Third: in the range based loop you have to define val as reference so you can modify it modifying also the referenced value inside the vector 第三:在基于范围的循环中,您必须将val定义为参考,以便您可以对其进行修改,同时修改向量内的参考值

// ........V   by reference
for ( auto & val : mc.data1() ) {
   ++val ;  // this modify the value in the vector inside mc
   cout << val << endl;
}

Considering data encapsulation, do you think it is bad practice to return a (const) reference to the two vectors? 考虑到数据封装,您是否认为对两个向量返回一个(const)引用是不好的做法?

IMHO: if the reference is const , not at all: it's a good practice because permit the safe use of the member without the need to duplicate it. 恕我直言:如果引用是const ,则根本不是:这是一个好习惯,因为允许安全使用该成员而无需重复该成员。

If the reference isn't const , I don't see big difference with declaring the member public. 如果引用不是const ,那么将成员声明为public不会有太大区别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM