Necesito plantilla de clase array C ++, que es de tamaño fijo, pila-basada y no requiere constructor predeterminado

StackOverflow https://stackoverflow.com/questions/3873625

Pregunta

Por lo tanto, he estado mirando impulso :: matriz, pero sí requiere un constructor por defecto definido. Creo que la mejor manera de llenar esta matriz con los datos, sería a través de un push_back (const T &) método. Llamándolo más veces que el tamaño (conocido en tiempo de compilación) daría lugar a afirmar o excepción, dependiendo de la configuración de generación. De esta manera siempre contendría datos significativos. ¿Alguien sabe eficiente aplicación portátil, y fiable de este concepto?

¿Fue útil?

Solución

Bueno, yo habría pensado que alguien hubiera traído la respuesta ahora, sin embargo, parece que no, así que vamos a ir.

Lo que está deseando para algo que yo he soñado: a. boost::optional_array<T,N>

Existen dos variantes:

  • Primero:. Similar a boost::array< boost::optional<T>, N >, que es cada elemento puede o no puede ser conjunto
  • Segundo:. Similar a un std::vector<T> (de alguna manera), es decir todos los elementos que comienzan y se establecen todas las siguientes no son

Teniendo en cuenta las anteriores preguntas / comentarios, parece que le gustaría que el segundo, pero en realidad no importa ya que ambos son bastante parecidos.

template <typename T, size_t N>
class stack_vector
{
public:
  bool empty() const { return mSize == 0; }
  size_t size() const { return mSize; }
  size_t capacity() const { return N; }
  size_t max_size() const { return N; }

  T& operator[](size_t i) { return *(this->pfront() + i); }
  /// ...

private:
  T* pfront() const { return reinterpret_cast<T*>(&mStorage); }

  std::aligned_storage< N * sizeof(T), alignof(T) > mStorage;
  size_t mSize; // indicate how many elements are set, from the beginning
};

El enfoque de Let en esas operaciones muy especiales:

template <typename T, size_t N>
void push_back(T const& t)
{
  new (this->pfront() + mSize) T(t); // in place construction
  ++mSize;
}

template <typename T, size_t N>
void clear()
{
  for (size_t i = 0; i != mSize; ++i)
  {
    (this->pfront() + i)->~T();
  }
  mSize = 0;
}

Como se puede notar, la principal dificultad es recordar que:

  • Si no hay ningún elemento se ha construido allí todavía, es necesario la colocación de nueva construcción + copia en su lugar de destino.
  • elementos que se convierten en "obsoleto" (es decir, sería después del último elemento) debe ser adecuadamente dispuesto de (es decir, su destructor ser invocada).

Hay muchas operaciones en el contenedor STL tradicional que puede ser difícil de implementar. En un vector, arrastrando los pies elemento (debido a insert o erase) son quizá los ejemplos más stricking.

Tenga en cuenta también que con C ++ 0x y inicializador-listas vector get emplace_back a construir directamente un elemento en su lugar, levantando así el requisito CopyConstructible, podría ser de gran ayuda agradable depende de su caso.

Otros consejos

boost::array<T, 12> ta; no es diferente de T[12] ta;; si no se utiliza una lista de inicialización a continuación los elementos serán por defecto construida.

La solución común sería boost::array<T*, 12> ta; o tal vez boost::array<unique_ptr<T>, 12> ta;.

La única forma de tienda de valor es la copia, hay forma de evitar que ... Esto es lo que inicializador listas de hacer:

struct A {
    A(int i):_i(i){ cout << "A(int)" << endl; }
    A(const A& a){ cout << "A(const A&)" << endl; }
    ~A(){ cout << "~A()" << endl; }

    int _i;
};

int main(){
    boost::array<A, 2> ta = {{1, 2}};
}

Este salidas:

A(int)
A(const A&)
A(int)
A(const A&)
~A()
~A()
~A()
~A()

http://codepad.org/vJgeQWk5

puede ser almacenar un impulso :: variante en su impulso :: matriz? hacer que el primer parámetro un int o algo ..

es decir.

boost::array<boost::variant<int, foo>, 6> bar;

bien lo que tiene que hacer frente a una variante, pero de pila asignado ...

En C ++ 0x tienes std::array<type, size> (probablemente el mismo que el impulso :: matriz). Puede inicializar la matriz de datos mediante el uso de fill() o std::fill_n():

std::array<int, 30> array;
array.fill(0);
boost::array<int, 30> barray;
std::fill_n(barray.begin(), 30, 0);

Si usted quiere conseguir que éste no pague-inicializa en la definición puede usar la copia-ctor:

static std::array<int, 30> const nullarray = {0, 0, 0, ..., 0}; // nullarray.fill(0);
// (...)
std::array<int, 30> array{nullarray};

¿Por qué tiene que residir en la pila? ¿Tiene evidencia empírica de que la creación y reserveing un vector es demasiado lento (utilizando un vector parece que la respuesta obvia)?

Incluso si lo es, se puede crear un conjunto de vectores que tienen espacio reservado y swap uno de los vectores preasignados en una copia local. Cuando haya terminado con la local, cambiarlo de nuevo (al igual que el truco para splice lists).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top