不可调整大小的向量/不可分配但可变成员的数组?

时间:2010-07-02 18:41:35

标签: c++ stl vector const

有没有办法制作一个不可重新调整的不可重新分配但可变成员的可调整大小的矢量/数组?我能想象的最接近的事情是使用从临时构造的vector<T *> const副本,但是因为我在初始化时知道​​有多少和我想要什么,我宁愿拥有一个对象块而不是指针。下面显示的内容可能与std::vector或更模糊的提升等模板有关吗?

// Struct making vec<A> that cannot be resized or have contents reassigned.
struct B {
  vector<A> va_; // <-- unknown modifiers or different template needed here
  vector<A> va2_;

  // All vector contents initialized on construction.
  Foo(size_t n_foo) : va_(n_foo), va2_(5) { }

  // Things I'd like allowed: altering contents, const_iterator and read access.
  good_actions(size_t idx, int val) {
    va_[idx].set(val);

    cout << "vector<A> info - " <<  " size: " << va_.size() << ", max: "
      << va_.max_size() << ", capacity: " << va_.capacity() << ", empty?: "
      << va_.empty() << endl;

    if (!va_.empty()) {
      cout << "First (old): " << va_[0].get() << ", resetting ..." << endl;
      va_[0].set(0);
    }

    int max = 0;
    for (vector<A>::const_iterator i = va_.begin(); i != va_.end(); ++i) {
      int n = i->get();
      if (n > max) { max = n; }
      if (n < 0)   { i->set(0); }
    }
    cout << "Max : " << max << "." << endl;
  }

  // Everything here should fail at compile.
  bad_actions(size_t idx, int val) {
    va_[0]    = va2_[0];
    va_.at(1) = va2_.at(3);

    va_.swap(va2_);
    va_.erase(va_.begin());
    va_.insert(va_.end(), va2_[0]);

    va_.resize(1);
    va_.clear();
    // also: assign, reserve, push, pop, .. 
  }
};

4 个答案:

答案 0 :(得分:2)

您的要求存在问题。但首先让我们解决固定大小的问题,它被称为std::tr1::array<class T, size_t N>(如果你知道编译时的大小)。

如果你在编译时不知道它,你仍然可以在向量上使用一些代理类。

template <class T>
class MyVector
{
public:
  explicit MyVector(size_t const n, T const& t = T()): mVector(n,t) {}

  // Declare the methods you want here
  // and just forward to mVector most of the time ;)

private:
  std::vector<T> mVector;
};

但是,如果你是可变的,那么不可转让的重点是什么?没有什么能阻止用户做繁重的工作:

class Type
{
public:
  int a() const { return a; }
  void a(int i) { a = i; }

  int b() const { return b; }
  void b(int i) { b = i; }
private:
  Type& operator=(Type const&);

  int a, b;
};

没有什么能阻止我这样做:

void assign(Type& lhs, Type const& rhs)
{
  lhs.a(rhs.a());
  lhs.b(rhs.b());
}

我只是想让你的生活变得复杂......

也许您可以更准确地描述您想要做什么,您是否希望限制类上可能的操作子集(某些变量不可能修改,但其他变量可能)?

在这种情况下,您可以再次使用Proxy类

class Proxy
{
public:
  // WARN: syntax is screwed, but `vector` requires a model
  // of the Assignable concept so this operation NEED be defined...
  Proxy& operator=(Proxy const& rhs)
  {
    mType.a = rhs.mType.a;
    // mType.b is unchanged
    return *this;
  }

  int a() const { return mType.a(); }
  void a(int i) { mType.a(i); }      

  int b() const { return mType.b(); }

private:
  Type mType;
};

使用合适的代理服务器并不是很多。这可能是我见过的最有用的模式。

答案 1 :(得分:1)

你能创建一个包含对象引用的类,但它的构造函数只能由它的std :: vector的朋友访问吗?

e.g:

template<typename T>
class MyRef {
   firend class std::vector< MyRef<T> >
public:
   T& operator->();
[...etc...]

答案 2 :(得分:1)

你问的是不可能的。

阻止分配内容的唯一方法是将该类型的operator =定义为private。 (作为对此的扩展,因为const operator =方法没有多大意义(并且因此不常见),您可以通过仅允许从容器访问const引用来接近这一点。但是用户仍然可以定义一个const operator =,你想要可变对象。)

如果您考虑一下,std::vector::operator []会返回对其包含的值的引用。使用赋值运算符将为operator =调用该值。这里完全绕过了std::vector(除了用于获取引用的operator[]调用之外),因此它(std::vector)不可能以任何方式覆盖调用operator =函数。

您直接访问容器中对象成员的任何操作都必须返回对该对象的引用,然后可以使用该引用来调用对象的operator =。因此,除非容器为其包含的对象实现代理,否则容器无法阻止其中的对象被分配,该对象具有不执行任何操作的私有赋值运算符并且转发对“真实”对象的其他调用,但是不允许直接访问真实对象(虽然如果这样做有意义,你可以返回真实对象的副本)。

答案 3 :(得分:0)

您可以通过std::vector const以及向量的structclass数据mutable来实现您的目标。您的set方法必须为const。这是一个与g ++一起工作的例子:

#include <vector>

class foo
{ 
public:
  foo () : n_ () {}
  void set(int n) const { n_ = n; }

private:

  mutable int n_;
};

int main()
{
  std::vector<foo> const a(3);  // Notice the "const".
  std::vector<foo> b(1);

  // Executes!
  a[0].set(1);

  // Failes to compile!
  a.swap(b);
}

这样您就无法以任何方式更改vector,但您可以修改mutable所拥有的对象的vector数据成员。以下是此示例的编译方式:

g++ foo.cpp 
foo.cpp: In function 'int main()':
foo.cpp:24: error: passing 'const std::vector<foo, std::allocator<foo> >' as 'this' argument of 'void std::vector<_Tp, _Alloc>::swap(std::vector<_Tp, _Alloc>&) [with _Tp = foo, _Alloc = std::allocator<foo>]' discards qualifiers

我能想到的一个缺点是,您必须更加了解代码的const-correctness,但这也不一定是个缺点。

HTH!

编辑/澄清:这种方法的目标不是完全失败const。相反,目标是使用标准C ++和STL来演示实现OP问题中提出的要求的方法。它不是理想的解决方案,因为它公开了const方法,允许更改用户可见的内部状态。当然这是这种方法的问题。