2015-04-23 10 views
5

Für eine meiner Anwendungen muss ich Vektor der Größe 2^35 generieren (die Größe meines RAM ist 96 GB, so kann dieser Vektor leicht in RAM passen).Speichern vieler Elemente in std :: vector C++

int main() 
{ 
    int i; 

    /* initialize random seed: */ 
    srand (time(NULL)); 

    vector<int> vec; 
    do { 
    i = rand() % 10 + 1; 
    vec.push_back(i); 
    } while ((vec.size()*sizeof(int))<pow(2,35)); 

    return 0; 
} 

Allerdings merke ich, dass meine Do While-Schleife unendlich ausgeführt wird. Einer der möglichen Gründe ist der Bereich vec.size() ist lang unsigned int, was sehr viel kleiner ist als die Anzahl der eingefügten Elemente, d. H. pow(2,35), aufgrund derer ich denke, dass es in einer Endlosschleife geht. Ich kann mich irren. Bitte korrigieren Sie mich, wenn ich falsch liege. Kann mir aber bitte jemand sagen wie ich mehr als pow(2,35) Nummern in vec einfügen kann.

gcc Version: 4.8.2

+1

Sind Sie sicher, dass es unendlich geht und nicht nur sehr lange dauert? Sie können diesen Vektor in kleinere aufteilen, wenn 'vec.size()' wirklich das Problem ist. –

+0

Ist 'sizeof (size_t)' auf Ihrem Computer 4? Sonst würde ich erwarten, dass es eine Weile dauert, um ein paar Milliarden Elemente einzufügen ... – Barry

+7

Besser Platz in diesem Fall reservieren. – Jarod42

Antwort

1

aktualisieren

Als Baum Augen Mit hervorgehoben hat, ist dieser Beitrag nicht wirklich die Frage beantworten, weil in seiner Plattform Bedingung 4 nicht gilt (sizeof(std::size_t) ist eigentlich 8). Ich verlasse diesen Beitrag hier jedoch, um ein Problem hervorzuheben, das bei der Portierung des Codes auftreten kann.

Original-Beitrag

Ein Problem, das ich sehe, ist die folgende. Nehmen wir an (die meisten Plattformen erfüllen diese Annahmen), dass

1) vec.size zurückgibt std::size_t (nicht garantiert);

2) sizeof liefert std::size_t (garantiert);

3) std::size_t ist ein vorzeichenloser Integertyp (garantiert);

4) sizeof(std::size_t) == 4 (nicht garantiert);

5) CHAR_BIT == 8 (nicht garantiert).

(Es sei daran erinnert, dass CHAR_BIT die Anzahl der Bits in einem char ist.)

Daher ist die Art der vec.size()*sizeof(int)std::size_t ist und sein Maximalwert ist 2^(sizeof(std::size_t)*CHAR_BIT) - 1 == 2^32 - 1 < 2^32 < 2^35. Daher ist vec.size()*sizeof(int) immer kleiner als 2^35.

+0

http://stackoverflow.com/questions/29822249/storing-many-elements-in-stdvector-c#comment47771391_29822249 Die Größe des Integer-Typs, den 'vector :: size' zurückgibt, ist 8 auf seinem System. –

+0

@BaummitAugen Ziemlich gut, ich habe noch nicht alle Kommentare gelesen (es sollte wohl deutlich gemacht werden, in der Post zu sein). Auf jeden Fall glaube ich, dass meine Antwort immer noch relevant ist, weil sie Probleme hervorhebt, die beim Schreiben von tragbarem Code auftreten können. –

2

Ich werde versuchen, einige Ihrer Probleme in einer einfachen Lösung zu adressieren:

Erstes Problem Sie Platz haben ist. Da Sie nur Zahlen von 1-10 benötigen, würde Ihnen ein int8_t viel besser dienen.

Sekunde ist Geschwindigkeit. std::vector macht eine Menge Zuteilungen und Neuzuweisungen hinter der Haube. Da Sie eine feste Größe haben, ist es meiner Meinung nach nicht notwendig, sie zu benutzen. Mit diesem Wissen werden wir ein einfaches Array und Threads verwenden, um die Leistung zu verbessern.

Hier ist der Code:

#include <array> 
#include <random> 
#include <thread> 
#include <cstdint> 
#include <memory> 
#include <chrono> 

// Since you only need numbers from 1-10, a single byte will work nicely. 
const uint64_t size = UINT64_C(0x800000000); // Exactly 2^35 
typedef std::array<int8_t, size> vec_t; 

// start is first element, end is one-past the last. This is a template so we can generate multiple functions. 
template<unsigned s> 
void fill(vec_t::iterator start, vec_t::iterator end) { 
    static const int seed = std::chrono::system_clock::now().time_since_epoch().count()*(s+1); 
    static std::default_random_engine generator(seed); 
    static std::uniform_int_distribution<int8_t> distribution(1,10); 
    for(auto it = start; it != end; ++it) { 
     *it = distribution(generator); // generates number in the range 1..10 
    } 
} 

int main() { 
    auto vec = std::unique_ptr<vec_t>(new vec_t()); 

    // Each will have its own generator and distribution. 
    std::thread a(fill<0>, vec->begin(), vec->begin() + size/4); 
    std::thread b(fill<1>, vec->begin() + size/4, vec->begin() + size/2); 
    std::thread c(fill<2>, vec->begin() + size/2, vec->begin() + (size/4)*3); 
    std::thread d(fill<3>, vec->begin() + (size/4)*3, vec->end()); 
    a.join(); 
    b.join(); 
    c.join(); 
    d.join(); 
    return 0; 
} 
+0

'int8_t vec [size];' Dies wird nicht funktionieren (auf den meisten Systemen). Normalerweise können Sie auf diese Weise nicht mehr als 8 MB erhalten. Die Verwendung von 'std :: vector' ist das Richtige, wenn Sie das Leerzeichen vor dem Ausfüllen reservieren, ist die Anzahl der Zuordnungen genau eins (das ist kleiner als *" viel "*). –

+0

mit einem Heap allokiert 'std :: array' (+' scoped_ptr') wäre am besten imho. 'reserve' funktioniert nicht so gut mit Threads .. da' push_back' nicht threadsicher ist. – smerlin

+0

Bevorzugen Sie std :: array zu c-array. – evan

2

Warum können Sie nicht Konstruktor verwenden?

std::vector<int> vec (number_of_elements); 

Auf diese Weise haben Sie Speicher reserviert, dann können Sie Elemente mit Generieren oder etwas randomisieren.

+1

Ich glaube, es ist schneller vec.reserve und dann push_back/emplace_back zu verwenden. Da Sie sowieso jeden vorhandenen Wert ändern müssen (Schleife durch den Vektor noch einmal), da der ctor-Standard den Typ konstruiert (es sei denn, Sie übergeben ihm einen Wert als zweiten Argument, aber das macht keinen Unterschied). –

+0

@ miguel.martin Wie kann ich herausfinden, ob reserve() die Menge an Arbeitsspeicher zugewiesen hat, die es zugewiesen hat, dh 34 GB –

+0

Wie kann ich herausfinden, ob der Konstruktor die Menge an Arbeitsspeicher zugewiesen hat, die er angefordert hat dh 34 GB –

Verwandte Themen