J'ai besoin d'un modèle de classe de tableau C++, de taille fixe, basé sur une pile et ne nécessitant pas de constructeur par défaut

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

Question

J'ai donc regardé boost::array mais cela nécessite la définition d'un constructeur par défaut.Je pense que la meilleure façon de remplir ce tableau avec des données serait d'utiliser une méthode push_back(const T&).L'appeler plus de fois que SIZE (connu au moment de la compilation) entraînerait une assertion ou une exception, selon la configuration de la construction.De cette façon, il contiendrait toujours des données significatives.Quelqu'un connaît-il une mise en œuvre efficace, portable et fiable de ce concept ?

Était-ce utile?

La solution

Eh bien, je l'aurais pensé que quelqu'un aurait apporté la réponse maintenant, mais il ne semble pas, alors allons-y.

Qu'est-ce que vous Souhaiter est quelque chose que je me suis rêvé. boost::optional_array<T,N> un

Il existe deux variantes:

  • Première:. Semblable à boost::array< boost::optional<T>, N >, qui est chaque élément peut ou peut ne pas être ensemble
  • Deuxième:. Semblable à un std::vector<T> (en quelque sorte), qui est tous les éléments débutants sont fixés et tous les suivants ne sont pas

Compte tenu des questions / commentaires précédents, il semble que vous voulez que le deuxième, mais il ne compte pas vraiment que les deux sont tout à fait semblables.

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'accent sur les opérations Soit très spéciales:

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

Comme vous pouvez le remarquer, la principale difficulté est de se rappeler que:

  • si aucun élément n'a été construit il y a encore, vous avez besoin d'une nouvelle construction placement + copie au lieu d'affectation.
  • éléments qui deviennent « obsolètes » (c.-à-serait après le dernier élément) doivent être éliminés de manière appropriée (leur destructor être invoquée).

Il y a de nombreuses opérations sur le contenant traditionnel STL qui peut être difficile à mettre en œuvre. Sur un vector, shuffling élément (en raison de insert ou erase) sont peut-être les exemples les plus de stricking.

Notez également que C ++ 0x et initialiseur-listes vector get emplace_back à construire directement un élément en place, soulevant ainsi l'exigence de CopyConstructible, pourrait être une aubaine agréable dépend de votre cas.

Autres conseils

boost::array<T, 12> ta; ne diffère pas de T[12] ta;; si vous n'utilisez pas une liste d'initialiseur alors les éléments seront par défaut construit.

La solution commune serait boost::array<T*, 12> ta; ou boost::array<unique_ptr<T>, 12> ta; peut-être.

La seule façon de stocker en valeur est de copier, pas moyen de contourner cela ... C'est ce que initialiseur listes font:

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

sorties:

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

http://codepad.org/vJgeQWk5

peut être stocker un coup de pouce :: variante dans votre boost :: tableau? faire le premier paramètre un entier ou quelque chose ..

i.e..

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

d'accord que vous avez à faire face à une variante, mais il est pile ... alloué

En C ++ 0x vous avez std::array<type, size> (probablement le même que boost :: tableau). Vous pouvez initialiser les données du tableau en utilisant fill() ou std::fill_n():

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

Si vous le voulez par défaut initialisé à la définition que vous pouvez utiliser le copier-cteur:

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

Pourquoi doit-il résider sur la pile ?Avez-vous des preuves empiriques que la création et reserveing un vector est trop lent (en utilisant un vector cela semble être la réponse évidente) ?

Même si c'est le cas, vous pouvez créer un pool de vecteurs avec un espace réservé et swap l'un des vecteurs pré-alloués dans une copie locale.Lorsque vous avez terminé avec le local, échangez-le à nouveau (un peu comme le splice truc pour lists).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top