Ich brauche C ++ Array Klassenvorlage, die mit fester Größe ist, Stack-basierte und erfordert keinen Standardkonstruktors

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

Frage

Also, ich habe bei boost :: Array aus, aber es erfordert Standard-Konstruktor definiert. Ich denke, der beste Weg, um dieses Array mit Daten zu füllen, durch einen push_back wäre (const T &) -Methode. Nennt es öfter als SIZE (zum Zeitpunkt der Kompilierung bekannt ist) würde in assert oder Ausnahme, abhängig von Build-Konfiguration. Auf diese Weise wäre es immer sinnvolle Daten enthalten. Weiß jemand, effiziente, portable, zuverlässige Umsetzung dieses Konzepts?

War es hilfreich?

Lösung

Nun, hätte ich gedacht, dass jemand jetzt die Antwort gebracht hätte, aber es scheint nicht, so geht sie.

Was Sie wollen, für etwas, was ich mir erträumt haben: a. boost::optional_array<T,N>

Es gibt zwei Varianten:

  • Erstens:. Ähnlich wie boost::array< boost::optional<T>, N >, dass jedes Element ist oder nicht eingestellt werden kann
  • Zweitens:. Ähnlich einem std::vector<T> (irgendwie), die alle Anfang Elemente gesetzt und alle folgenden diejenigen sind nicht

In Anbetracht der vorherigen Fragen / Kommentare, es scheint, dass Sie die zweite möchten, aber es ist nicht wirklich wichtig, da beide ziemlich gleich sind.

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

Lassen Sie uns Fokus auf diesen ganz besonderen Operationen:

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

Wie Sie sehen können, die größte Schwierigkeit besteht darin, dass sich daran zu erinnern:

  • , wenn kein Element dort noch gebaut wurde, müssen Sie die Platzierung neuer + Kopie Bau statt Zuordnung.
  • -Elemente, die „überholt“ werden (dh nach dem letzten Element wäre) sollte ordnungsgemäß entsorgt werden (dh ihre destructor aufgerufen werden).

Es gibt viele Operationen auf traditionelle STL-Container, die schwierig sein kann, zu implementieren. Auf einem vector, Element schlurfenden (wegen insert oder erase) sind vielleicht die stricking Beispiele.

Beachten Sie auch, dass mit C ++ 0x und initializer-Listen vector get emplace_back direkt ein Element an Ort und Stelle zu konstruieren, so dass die CopyConstructible Anforderung heben, könnte einen schönen Segen abhängig von Ihrem Fall sein.

Andere Tipps

boost::array<T, 12> ta; unterscheidet sich nicht von T[12] ta;; wenn Sie eine Initialisiererliste nicht verwenden, dann werden die Elemente sein Standard aufgebaut.

Die gemeinsame Abhilfe boost::array<T*, 12> ta; wäre oder vielleicht boost::array<unique_ptr<T>, 12> ta;.

Die einzige Möglichkeit zum Speichern von Wert zu kopieren ist, keinen Weg dran vorbei ... Das ist, was initializer Listen tun:

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

Diese Ausgänge:

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

http://codepad.org/vJgeQWk5

kann sein, speichern Sie eine boost :: Variante in Ihrem boost :: array? macht den erste Parameter ein int oder etwas ..

d.

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

okay, müssen Sie mit einer Variante umgehen, aber es ist Stapel reserviert ...

In C ++ 0x Sie bekam std::array<type, size> (wahrscheinlich das gleiche wie boost :: array). Sie können Array-Daten initialisieren, indem fill() oder std::fill_n() mit:

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

Wenn Sie wollen, dass es bei der Bestimmung erhalten default-initialisiert können Sie copy-Ctor verwenden:

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

Warum muss es auf dem Stapel wohnen? Haben Sie empirische Beweise haben, dass die Erstellung und reserveing eine vector ist zu langsam (unter Verwendung eines vector scheint, wie die offensichtliche Antwort)?

Auch wenn es ist, können Sie einen Pool von Vektoren erzeugen, die Platz haben, reserviert und swap einer der vorab zugewiesenen Vektoren in eine lokale Kopie. Wenn Sie mit dem lokalen ein fertig sind, tauschen sie wieder zurück (ähnlich wie die splice Trick für lists).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top