Ho bisogno di C ++ modello di classe array, che è di dimensioni fisse, stack-based e non richiede costruttore predefinito

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

Domanda

Quindi, ho cercato a boost :: serie ma richiede costruttore di default definito. Credo che il modo migliore di colmare questa matrice con i dati, sarebbe attraverso un push_back (const T &) metodo. Chiamarlo più volte del formato (noto al momento della compilazione) comporterebbe affermare o eccezione, a seconda della configurazione di generazione. In questo modo sarebbe sempre contenere dati significativi. Qualcuno sa efficiente, portatile, affidabile attuazione di questo concetto?

È stato utile?

Soluzione

Beh, avrei pensato che qualcuno avrebbe portato la risposta ora, tuttavia non sembra, quindi cerchiamo di andare.

Cosa si desiderano per è qualcosa che ho sognato io:. Un boost::optional_array<T,N>

Ci sono due varianti:

  • Prima:. Simile a boost::array< boost::optional<T>, N >, cioè ciascun elemento può o non può essere impostato
  • . Secondo: simile ad un std::vector<T> (in qualche modo), che è di tutti gli elementi che iniziano vengono impostate e tutti quelli successivi non sono

Date le precedenti domande / osservazioni, sembra che si desidera che il secondo, ma non importa quanto entrambi sono abbastanza simili.

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

L'attenzione di Let su quelle operazioni molto speciali:

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

Come si può notare, la difficoltà principale è quello di ricordare che:

  • Se nessun elemento è stato costruito ancora lì, è necessario il posizionamento di nuova costruzione + copia anziché di assegnazione.
  • elementi che diventano "obsolete" (cioè sarebbe dopo l'ultimo elemento) devono essere adeguatamente smaltiti (cioè la loro destructor richiamato).

Ci sono molte operazioni sul contenitore STL tradizionale che può essere difficile da implementare. Su un vector, elemento di rimescolamento (a causa di insert o erase) sono forse gli esempi più stricking.

Si noti inoltre che con il C ++ 0x e inizializzatore-liste vector get emplace_back a costruire direttamente un elemento al suo posto, sollevando così il requisito CopyConstructible, potrebbe essere un bel vantaggio dipende dal vostro caso.

Altri suggerimenti

boost::array<T, 12> ta; non è diverso da T[12] ta;; se non si utilizza una lista di inizializzazione quindi gli elementi saranno di default costruito.

La soluzione comune sarebbe boost::array<T*, 12> ta; o forse boost::array<unique_ptr<T>, 12> ta;.

L'unico modo per negozio per valore è quello di copiare, nessun modo per aggirare questo ... Questo è quello che inizializzatore liste fare:

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

Questa uscite:

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

http://codepad.org/vJgeQWk5

può essere memorizzare un boost :: variante in vostro boost :: array? fare il primo parametro di un int o qualcosa del genere ..

cioè.

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

va bene hai a che fare con una variante, ma di pila assegnato ...

In C ++ 0x hai std::array<type, size> (probabilmente lo stesso boost :: array). È possibile inizializzare i dati dell'array utilizzando 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);

Se si vuole farlo default-inizializzato a definizione è possibile utilizzare copia-ctor:

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

Perché deve risiedere sullo stack? Avete evidenza empirica che la creazione e reserveing un vector è troppo lento (utilizzando un vector sembra che la risposta ovvia)?

Anche se si tratta, è possibile creare un pool di vettori che dispongono di spazio riservato e swap uno dei vettori pre-assegnati in una copia locale. Quando hai finito con quello locale, scambiare di nuovo indietro (molto simile il trucco splice per lists).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top