6

クラスには。が含まれますstd::vector<int*>。外部コードは、このベクトルへの読み取り専用アクセスを必要とし、コンテンツ(ポインターまたはそのコンテンツのいずれも)を変更できないようにする必要があります。クラス内では、値変更される可能性があります(たとえばdouble_values()、など、値をaとして保存することstd::vector<const int*>はできません。

コピーを作成せずにをstd::vector<int*>として返す方法はありますか?std::vector<const int*>constはコンパイル時に何を変更できるか、何を変更できないかを言うために動作しているだけなので、あるべきだと感じます。

コード:(でコンパイルg++ -std=c++0x

class ReadOnlyAccess
{
public:
  ReadOnlyAccess(const std::vector<int*> & int_ptrs_param):
    int_ptrs(int_ptrs_param)
  {
  }
  const std::vector<int*> & get_int_ptrs() const
  {
    return int_ptrs;
  }
  std::vector<const int*> safely_get_int_ptrs() const
  {
    // will not compile (too bad):
    //    return int_ptrs;

    // need to copy entire vector
    std::vector<const int*> result(int_ptrs.size());
    for (int k=0; k<int_ptrs.size(); k++)
      result[k] = int_ptrs[k];
    return result;
  }
  void double_values()
  {
    for (int*p : int_ptrs)
      *p *= 2;
  }
  void print() const
  {
    for (const int * p : int_ptrs)
      std::cout << *p << " ";
    std::cout << std::endl;
  }
private:
  std::vector<int*> int_ptrs;
};

int main() {
  ReadOnlyAccess roa(std::vector<int*>{new int(10), new int(20), new int(100)});
  std::vector<const int*> safe_int_ptrs = roa.safely_get_int_ptrs();
  // does not compile (good)
  // *safe_int_ptrs[0] = -100000;
  roa.print();

  const std::vector<int*> & int_ptrs = roa.get_int_ptrs();
  // changes are made to the internal class values via the accessor! nooooo!
  *int_ptrs[0] = -100000;
  roa.print();

  return 0;
}
4

2 に答える 2

4

とにかく const ポインタを保持したい場合、ベクトルを返すことはコピーを意味します。

ただし、値を変更したりコンテナーを変更したりせずに値を使用する方法を提供することが目標である場合は、特にラムダ式を使用できるようになったため、ビジター パターン ベースのアルゴリズムが非常に優れたソリューションになる可能性があります。

#include <vector>
#include <iostream>

class Data
{
public:

    //...whatever needed to fill the values

    // here we assume that Func is equivalent to std::function< void ( int )> or std::function< void (const int& ) > and can return anything that will be ignored here.
    template< class Func > 
    void for_each_value( Func func ) const // read-only
    {
        for( const int* value : m_values ) // implicit conversion
        {
             func( *value ); // read-only reference (const &), or copy
             // if func needs to work with the adress of the object, it still can by getting a reference to it and using & to get it's adress
        }
    }


    void print() const
    {
        std::cout << "\nData values: \n";
        for_each_value( []( const int value ) { std::cout << "    "<< value << '\n'; } );
    }

    void count_values() const { return m_values.size(); }

private:

    std::vector<int*> m_values;

};



int main()
{
    Data data;
    // ... whatever needed to fill the data

    data.print();    

    std::vector<int> modified_values;
    data.for_each_value( [&]( int value ) { modified_values.push_back( value + 42 ); } );

    return 0;
}

それを理解し、値を使用するさまざまな方法をいくつかの半分ジェネリックなアルゴリズムに減らすことができれば、コードがより単純になり、データを内部に公開する代わりに構造内に保持できるようになります。

于 2012-04-22T07:00:05.577 に答える
1

カスタム イテレータを介して const 値へのビューを提供できます。簡単な方法は、次を使用することboost::iteratorです。

#include <boost/iterator/indirect_iterator.hpp>

class ReadOnlyAccess
{
// ...
    typedef boost::indirect_iterator<const int* const*, const int> const_val_iter_type;
    const_val_iter_type cval_begin() {
        return it_t{const_cast<const int* const*>(&int_ptrs[0])};
    }
}

int main() {
    // ...
    auto x = roa.cval_begin();
    std::cout << x[0] <<' ' << x[1] << x[2] <<'\n';
    // we can still access the pointers themselves via .base() member function:
    for (int i=0; i<3; ++i)
        assert(x.base()[i] == safe_int_ptrs[i]);
    // the values are read-only, the following does not compile:
    // x[0] = -1;
    // **x.base() = -1;
    // *x.base() = nullptr;
}

boost::indirect_iterator<typename std::vector<int*>::const_iterator, const int>forを使用した場合、ポイントされconst_val_iter_typeた値を経由で変更できます.base()(ただし、たとえば のように直接変更することはできませんx[0] = -1)。したがって、この解決策は一般的ではありません。

于 2012-04-22T11:11:34.467 に答える