c++ - একটি স্টাড:: ভেক্টরের শেষে সন্নিবেশ বা পুশ_ব্যাক?




performance c++11 (3)

সর্বোপরি, তারা একই জিনিস করে। তারা না?

না। তারা আলাদা। std::vector::push_back ব্যবহার করে প্রথম পদ্ধতিটি std::vector::push_back std::vector::insert তুলনায় বেশ কয়েকটি পুনঃনির্ধারণের std::vector::push_back যাবে।

insert অভ্যন্তরীণভাবে মেমরির বরাদ্দ করবে, বর্তমান std::vector::capacity অনুযায়ী সীমাটি অনুলিপি করার আগে। আরও তথ্যের জন্য নিম্নলিখিত আলোচনা দেখুন:

এসডিডি :: ভেক্টর :: সংজ্ঞা দিয়ে রিজার্ভ sertোকান?

তবে কি পারফরম্যান্সে কোনও পার্থক্য রয়েছে?

উপরে বর্ণিত কারণের কারণে, দ্বিতীয় পদ্ধতিতে সামান্য পারফরম্যান্সের উন্নতি দেখাবে। উদাহরণস্বরূপ, নীচে দ্রুত বেন-চিহ্নটি দেখুন, http://quick-bench.com ব্যবহার করে:

অনলাইন বেঞ্চ-চিহ্ন দেখুন

বা পারফরম্যান্সটি পরিমাপ করার জন্য একটি পরীক্ষা প্রোগ্রাম লিখুন (মন্তব্যগুলিতে @ কিছু প্রোগ্রামার বংশোদ্ভূত হিসাবে)। নীচে একটি নমুনা পরীক্ষা প্রোগ্রাম:

vec.insert(std::end(vec), std::begin(arr), std::end(arr));

আমার সিস্টেমের সাথে বিল্ডিং রিলিজ করুন (এমএসভিএস ২০১২: / অক্স / এসটিডি: সি ++ ১ 17 , এএমডি রাইজন 7 2700x (8-কোর, 3.70 গিগাহার্টজ , এক্স 64 উইন্ডোজ 10 )

#include <iostream>
#include <chrono>
#include <algorithm>
#include <vector>
using namespace std::chrono;

class Timer final
{
private:
    time_point<high_resolution_clock> _startTime;

public:
    Timer() noexcept
        : _startTime{ high_resolution_clock::now() }
    {}
    ~Timer() noexcept {  Stop(); }
    void Stop() noexcept
    {
        const auto endTime = high_resolution_clock::now();
        const auto start = time_point_cast<microseconds>(_startTime).time_since_epoch();
        const auto end = time_point_cast<microseconds>(endTime).time_since_epoch();
        const auto durationTaken = end - start;
        const auto duration_ms = durationTaken * 0.001;
        std::cout << durationTaken.count() << "us (" << duration_ms.count() << "ms)\n";
    }
};
// Method 1: push_back
void push_back()
{
    std::cout << "push_backing:    ";
    Timer time{};
    for (auto i{ 0ULL }; i < 1000'000; ++i)
    {
        std::vector<int> vec = { 1 };
        vec.push_back(2);
        vec.push_back(3);
        vec.push_back(4);
        vec.push_back(5);
    }
}
// Method 2: insert_range
void insert_range()
{
    std::cout << "range-inserting: ";
    Timer time{};
    for (auto i{ 0ULL }; i < 1000'000; ++i)
    {
        std::vector<int> vec = { 1 };
        int arr[] = { 2,3,4,5 };
        vec.insert(std::end(vec), std::cbegin(arr), std::cend(arr));
    }
}

int main()
{
    push_back();
    insert_range();
    return 0;
}

প্রদত্ত দৃশ্যের জন্য কোনটি দেখায়, std::vector::insert std::vector::push_back চেয়ে প্রায় std::vector::push_back times গুন দ্রুত।

অন্যান্য সংকলক ( ক্ল্যাং ৮.০ এবং জিসিসি ৯.২ ) তাদের বাস্তবায়ন অনুযায়ী কি বলতে চায় তা দেখুন: https://godbolt.org/z/DQrq51

std::vector শেষে নতুন উপাদানগুলি সন্নিবেশ করানোর জন্য নীচের দুটি পদ্ধতির মধ্যে পারফরম্যান্সের কোনও পার্থক্য রয়েছে:

পদ্ধতি 1

std::vector<int> vec = { 1 };
vec.push_back(2);
vec.push_back(3);
vec.push_back(4);
vec.push_back(5);

পদ্ধতি 2

std::vector<int> vec = { 1 };
int arr[] = { 2,3,4,5 };
vec.insert(std::end(vec), std::begin(arr), std::end(arr));

ব্যক্তিগতভাবে, আমি পদ্ধতি 2 পছন্দ করি কারণ এটি দুর্দান্ত এবং সংক্ষিপ্ত এবং একযোগে অ্যারে থেকে সমস্ত নতুন উপাদান সন্নিবেশ করায়। কিন্তু

  • পারফরম্যান্সে কি কোনও পার্থক্য আছে?
  • সর্বোপরি, তারা একই জিনিস করে। তারা না?

হালনাগাদ

যে কারণে আমি সমস্ত উপাদানগুলির সাথে ভেক্টরটি আরম্ভ করছি না, তার কারণটি হ'ল এটি আমার প্রোগ্রামটিতে আমি একটি শর্তের ভিত্তিতে অবশিষ্ট উপাদান যুক্ত করছি।


প্রধান অবদানকারী ফ্যাক্টরটি আবার বরাদ্দ হতে চলেছে। vector নতুন উপাদানগুলির জন্য জায়গা তৈরি করতে হবে।

এই 3 সিনপেট বিবেচনা করুন।

 //pushback
 std::vector<int> vec = {1};
 vec.push_back(2);
 vec.push_back(3);
 vec.push_back(4);
 vec.push_back(5);

 //insert
 std::vector<int> vec = {1};
 int arr[] = {2,3,4,5};
 vec.insert(std::end(vec), std::begin(arr), std::end(arr));


 //cosntruct
 std::vector<int> vec = {1,2,3,4,5};

ছবিতে ফিরে আসা পুনঃনির্ধারণগুলি নিশ্চিত করতে, vec.reserve(5) এবং সন্নিবেশিত সংস্করণগুলিতে একটি vec.reserve(5) যুক্ত করার পরে, আমরা নীচের ফলাফলগুলি পেয়েছি।


push_back একটি একক উপাদান সন্নিবেশ করায়, তাই সবচেয়ে খারাপ ক্ষেত্রে আপনি একাধিক পুনঃনির্ধারণের মুখোমুখি হতে পারেন।

উদাহরণস্বরূপ, ক্ষেত্রে বিবেচনা করুন যেখানে প্রাথমিক ক্ষমতাটি 2 এবং প্রতিটি পুনর্বিবেচনার ক্ষেত্রে 2 এর গুণক দ্বারা বৃদ্ধি পায়। তারপর

std::vector<int> vec = { 1 }; 
vec.push_back(2);             
vec.push_back(3);                 // need to reallocate, capacity is 4
vec.push_back(4);                   
vec.push_back(5);                  // need to reallocate, capacity is 8

আপনি অবশ্যই কল করে অহেতুক পুনঃনির্মাণগুলি প্রতিরোধ করতে পারেন

vec.reserve(num_elements_to_push);

যদিও আপনি যদি কোনও অ্যারে থেকে সন্নিবেশ করেন তবে সন্নিবেশ ব্যবহার করা আরও মূর্তিযুক্ত উপায়।







insert