كيف يمكنك نسخ محتويات الصفيف إلى std::المتجهات في C++ بدون حلقات?

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

  •  06-07-2019
  •  | 
  •  

سؤال

لدي مجموعة من القيم التي يتم تمريرها إلى وظيفة من جزء مختلف من البرامج التي تحتاج إلى تخزين للمعالجة فيما بعد.منذ أنا لا أعرف كم مرة وظيفتي سوف يطلق قبل أن الوقت قد حان لمعالجة البيانات, أنا بحاجة إلى ديناميكية بنية تخزين لذا اختار std::vector.أنا لا أريد أن تفعل القياسية حلقة push_back جميع القيم بشكل فردي ، فإنه سيكون من الرائع إذا كان بإمكاني فقط نسخ ذلك استخدام شيء مشابه memcpy.

هل كانت مفيدة؟

المحلول

إذا يمكنك بناء ناقلات بعد أن كنت قد حصلت على مجموعة ومجموعة الحجم، يمكنك أن تقول فقط:

std::vector<ValueType> vec(a, a + n);

... على افتراض a هو مجموعة وn هو عدد العناصر التي يحتوي عليها. وإلا فإن std::copy() ث / resize() تفعل خدعة.

وسوف أظل بعيدا عن memcpy() ما لم تتمكن من التأكد من أن القيم البيانات سهل من العمر (POD) أنواع.

وبالإضافة إلى ذلك، تجدر الإشارة إلى أن أيا من هذه يتجنب حقا للحلقة - انها مجرد مسألة ما إذا كان لديك لنرى ذلك في التعليمات البرمجية الخاصة بك أم لا. O (ن) أداء وقت التشغيل أمر لا مفر منه لنسخ القيم.

وأخيرا، لاحظ أن صفائف على غرار C هي حاويات صحيحة تماما بالنسبة لمعظم خوارزميات STL - مؤشر الخام ما يعادل begin()، و(ptr + n) ما يعادل end()

.

نصائح أخرى

كانت هناك العديد من الإجابات هنا فقط عن كل منهم سوف تحصل على هذه المهمة.

ومع ذلك هناك بعض مضللة المشورة!

هنا الخيارات:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

لخفض قصة قصيرة طويلة طريقة 4, باستخدام vector::إدراج, هو أفضل بالنسبة bsruth سيناريو.

وإليك بعض التفاصيل:

الأسلوب 1 هو على الأرجح أسهل للفهم.مجرد نسخ كل عنصر من الصفيف ودفعها إلى الجزء الخلفي من ناقلات.للأسف, انها بطيئة.لأن هناك حلقة (ثلاث نسخ) وظيفة كل عنصر يجب أن يعامل بشكل فردي ؛ أي تحسينات في الأداء يمكن أن تكون مصنوعة على أساس حقيقة أن نعرف مجموعة ناقلات كتل متجاورة.

الطريقة 2 هو اقترح تحسين الأداء إلى الأسلوب 1;فقط قبل الاحتياطي حجم المصفوفة قبل إضافته.على صفائف كبيرة هذا قد مساعدة.ومع ذلك فإن أفضل نصيحة هنا أبدا إلى استخدام الاحتياطي إلا إذا التنميط تشير إلى أنك قد تكون قادرة على تحسين (أو كنت بحاجة للتأكد من التكرار لن تكون يبطل). Bjarne يوافق.بالمناسبة, لقد وجدت أن هذا الأسلوب يقوم أبطأ معظم الوقت على الرغم من أنا تكافح من أجل شامل يفسر لماذا كان بانتظام بشكل كبير أبطأ من الطريقة 1...

طريقة 3 هو المدرسة القديمة الحل - رمي بعض ج في مشكلة!يعمل بشكل جيد و سريع جراب أنواع.في هذه الحالة تغيير حجم يشترط أن يكون دعا منذ memcpy يعمل خارج حدود ناقلات وليس هناك طريقة لمعرفة ناقلات أن حجمها قد تغير.وبصرف النظر عن كونها قبيحة الحل (بايت نسخ!) تذكر أن هذا يمكن أن إلا أن استخدام جراب أنواع.أنا لم استخدم هذا الحل.

الأسلوب 4 هو أفضل وسيلة للذهاب.إنه المعنى واضح ، هو (عادة) أسرع ويعمل على أي الكائنات.فلا ضير من استخدام هذه الطريقة للحصول على هذا التطبيق.

طريقة 5 هو قرص على طريقة 4 - نسخ مجموعة ناقلات ومن ثم إلحاق ذلك.خيار جيد - سريع عموما العش و واضحة.

أخيرا, هل تعلم أنه يمكنك استخدام المتجهات في مكان المصفوفات, صحيح ؟ حتى عندما تتوقع وظيفة ج-أسلوب المصفوفات يمكنك استخدام المتجهات:

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

على أمل أن يساعد شخص هناك!

إذا كل ما تقوم به هو استبدال البيانات الموجودة، ثم يمكنك القيام بذلك

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}

وبما أنني لا يمكن إلا أن تعديل الإجابة الخاصة بي، وأنا ذاهب إلى جعل إجابة مركبة من الإجابات الأخرى على سؤالي. شكر لكم جميعا الذين أجابوا.

الأمراض المنقولة جنسيا :: نسخ ، وهذا بالتكرار لا يزال في الخلفية، ولكن لم يكن لديك لكتابة خارج القانون.

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

memcpy . ربما يكون أفضل استخدام هذا لأنواع البيانات الأساسية (أي عدد صحيح) ولكن ليس للصفائف أكثر تعقيدا من البنيات أو فئات.

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source

unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

std::vector<int> myvector (dataArraySize );//target

std::copy ( myints, myints+dataArraySize , myvector.begin() );

//myvector now has 1,2,3,...10 :-)

وتجنب memcpy، وأنا أقول. لا يوجد سبب للفوضى مع عمليات المؤشر إلا إذا كنت حقا لل. أيضا، وأنها ستعمل فقط لأنواع POD (مثل كثافة العمليات)، ولكن ستفشل إذا كنت تتعامل مع الأنواع التي تتطلب البناء.

وبالإضافة إلى الأساليب الواردة أعلاه، تحتاج إلى تأكد من استخدام إما الأمراض المنقولة جنسيا :: Vector.reserve ()، الأمراض المنقولة جنسيا :: Vector.resize ()، أو بناء ناقلات لحجمها، للتأكد من ناقلات لديه ما يكفي من العناصر في ذلك لعقد البيانات الخاصة بك. إن لم يكن، وسوف الذاكرة الفاسدة. وهذا ينطبق على أي من الأمراض المنقولة جنسيا :: نسخة () أو memcpy ().

وهذا هو السبب في استخدام vector.push_back ()، لا يمكن أن يكتب بعد نهاية متجه.

ولكن إجابة أخرى، منذ قال شخص "أنا لا أعرف كم مرة سوف يطلق وظيفتي"، يمكن استخدام الأسلوب إدراج ناقلات مثل ذلك إلى إلحاق صفائف القيم إلى نهاية الموجه:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

وأنا أحب هذه الطريقة لأنه يجب أن يكون تنفيذ ناقلات قادرة على تحسين عن أفضل وسيلة لادخال القيم بناء على نوع مكرر ونوع نفسها. كنت ترد إلى حد ما عن تنفيذ المحكمة الخاصة بلبنان.

إذا كنت بحاجة لضمان سرعة أسرع وأنت تعرف نوع الخاص بك هو نوع POD ثم أنصح طريقة تغيير حجم ردا توماس:

vector<int> x;

void AddValues(int* values, size_t size)
{
   size_t old_size(x.size());
   x.resize(old_size + size, 0);
   memcpy(&x[old_size], values, size * sizeof(int));
}

وعلى افتراض انك تعرف كيف كبيرة هذا البند في ناقلات هم:

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

http://www.cppreference.com/wiki/stl/vector/start

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top