লুপিং ছাড়াই আপনি কীভাবে একটি অ্যারের উপাদানগুলি স্টাড :: ভেক্টরকে সি ++ এ অনুলিপি করবেন?


122

আমার কাছে প্রোগ্রামগুলির ভিন্ন অংশ থেকে আমার ফাংশনে পাস করা মানগুলির একটি অ্যারে রয়েছে যা পরবর্তী প্রসেসিংয়ের জন্য আমার সংরক্ষণ করতে হবে। যেহেতু আমি জানি না যে ডেটা প্রক্রিয়া করার সময় হওয়ার আগে আমার ফাংশনটি কতবার ডাকা হবে, তাই আমার একটি গতিশীল স্টোরেজ কাঠামো প্রয়োজন, তাই আমি একটিটি বেছে নিয়েছি std::vector। আমি push_backসমস্ত মানগুলিতে স্বতন্ত্রভাবে স্ট্যান্ডার্ড লুপটি করতে চাই না , এটির মতো কিছু ব্যবহার করে আমি কেবল সমস্তগুলি অনুলিপি করতে পারলে ভাল লাগবে memcpy

উত্তর:


117

অ্যারে এবং অ্যারের আকার অর্জনের পরে যদি আপনি ভেক্টরটি তৈরি করতে পারেন তবে আপনি কেবল বলতে পারেন:

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

... ধরে aনেওয়া আপনার অ্যারে এবং nএতে থাকা উপাদানগুলির সংখ্যা। অন্যথায়, std::copy()ডাব্লু / resize()কৌশলটি করবে।

memcpy()মানগুলি সরল-পুরাতন ডেটা (পিওডি) প্রকারের না তা আপনি নিশ্চিত না করতে পারলে আমি এ থেকে দূরে থাকতাম ।

এছাড়াও, লক্ষণীয় যে এগুলির কোনওটিই লুপের জন্য সত্যই এড়ানো যায় না - এটি আপনার কোডে দেখতে হবে কিনা তা কেবল একটি প্রশ্ন। ও (এন) রানটাইম পারফরম্যান্স মানগুলি অনুলিপি করার জন্য অনিবার্য।

পরিশেষে, নোট করুন যে সি-স্টাইলের অ্যারেগুলি বেশিরভাগ এসটিএল অ্যালগরিদমের জন্য পুরোপুরি বৈধ ধারক - কাঁচা পয়েন্টারটি সমান begin(), এবং ( ptr + n) এর সমতুল্য end()


4
লুপিং করা এবং পুশ_ব্যাক কল করার কারণটি খারাপ কারণ আপনি অ্যারে যথেষ্ট দীর্ঘ হলে ভেক্টরকে একাধিকবার পুনরায় আকার দিতে বাধ্য করতে পারেন।
bradtgmurray

@ ব্র্যাডটগমুর্রে: আমি মনে করি যে "দু'টি পুনরায়" ভেক্টর কনস্ট্রাক্টরের আমি প্রস্তাবিত যে কোনও কার্যকর প্রয়োগের জন্য প্রয়োজনীয় সংখ্যক উপাদানগুলির জন্য দুটি পুনরায় পুনরুদ্ধারে প্রথমে স্টাড :: দূরত্ব () কল করা হবে, তারপরে মাত্র একবার বরাদ্দ করুন।
ড্রয় হল

4
@ ব্র্যাডটগমুররে: ভেক্টরগুলির ঘনিষ্ঠভাবে বৃদ্ধি (যেমন "" ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে সময় কাটাতে হবে ") বৃদ্ধির কারণে এমনকি পুশ_ব্যাক () খুব খারাপ হবে না। আমি মনে করি রানটাইমটি সবচেয়ে খারাপ ক্ষেত্রে 2x এর চেয়ে বেশি খারাপ আদেশে থাকবে।
ড্র হলের

2
এবং যদি ভেক্টর ইতিমধ্যে সেখানে থাকে তবে একটি ভেক্টার ক্লিয়ার (); vec.insert (vec.begin (), a, a + n); পাশাপাশি কাজ করবে। তারপরে আপনার এমনকি পয়েন্টার হওয়ার দরকার নেই, কেবল একটি পুনরাবৃত্তকারী এবং ভেক্টর নিয়োগটি ব্যর্থতা সাধারণ (এবং সি ++ / এসটিএল উপায়) হবে।
এমপি 24

6
নির্মাণ করতে অক্ষম হলে অন্য একটি বিকল্প হ'ল : vec.assign(a, a+n)এটি অনুলিপি ও আকার পরিবর্তনের চেয়ে কমপ্যাক্ট।
এম মন্টু

209

এখানে অনেক উত্তর এসেছে এবং প্রায় সবগুলিই কাজটি সম্পন্ন করবে।

তবে কিছু বিভ্রান্তিকর পরামর্শ আছে!

এখানে বিকল্পগুলি:

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 কাটা, ভেক্টর :: সন্নিবেশ ব্যবহার করে বিস্রুতের দৃশ্যের জন্য সেরা।

এখানে কিছু বিষণ্ণ বিবরণ দেওয়া হল:

পদ্ধতি 1 বোঝার জন্য সম্ভবত সবচেয়ে সহজ। অ্যারে থেকে কেবল প্রতিটি উপাদান অনুলিপি করুন এবং এটি ভেক্টরের পিছনে চাপুন। হায়রে, এটা ধীর। যেহেতু একটি লুপ আছে (অনুলিপি ফাংশন দিয়ে বোঝানো), প্রতিটি উপাদান পৃথকভাবে চিকিত্সা করা উচিত; আরে এবং ভেক্টরগুলি সংকীর্ণ ব্লকগুলি এই সত্যের ভিত্তিতে কোনও পারফরম্যান্সের উন্নতি করা যায় না।

পদ্ধতি 2 পদ্ধতি 1 এর প্রস্তাবিত কার্যকারিতা উন্নতি; অ্যারের যোগ করার আগে এটির আকারটি কেবল সংরক্ষণ করুন। বড় অ্যারেগুলির জন্য এটি সহায়তা করতে পারে। তবে এখানে সর্বোত্তম পরামর্শটি কখনই রিজার্ভ ব্যবহার করা উচিত নয় যতক্ষণ না প্রোফাইলিং পরামর্শ দেয় আপনি উন্নতি করতে সক্ষম হতে পারেন (বা আপনার পুনরুক্তিগুলি অবৈধ হতে যাচ্ছে না তা নিশ্চিত করার প্রয়োজন)। বর্জন একমত । ঘটনাক্রমে, আমি দেখতে পেয়েছি যে এই পদ্ধতিটি বেশিরভাগ সময়ই সবচেয়ে ধীরে সম্পাদিত হয়েছিল যদিও আমি বিস্তৃতভাবে ব্যাখ্যা করার জন্য লড়াই করছি যে কেন এটি নিয়মিতভাবে পদ্ধতি 1 এর চেয়ে উল্লেখযোগ্যভাবে ধীর হয় ...

পদ্ধতি 3 হ'ল পুরাতন স্কুল সমাধান - সমস্যাটিতে কিছু সি ফেলে দিন! পিওডি ধরণের জন্য সূক্ষ্ম এবং দ্রুত কাজ করে। এক্ষেত্রে মাইজপি ভেক্টরের সীমানার বাইরে কাজ করে এবং কোনও ভেক্টরকে বলার উপায় নেই যে এর আকার পরিবর্তন হয়েছে। কদর্য সমাধান ছাড়াও (বাইট অনুলিপি করুন!) মনে রাখবেন যে এটি কেবল পিওডি ধরণের জন্য ব্যবহার করা যেতে পারে । আমি এই সমাধানটি কখনই ব্যবহার করব না।

পদ্ধতি 4 যাওয়ার সর্বোত্তম উপায়। এর অর্থ পরিষ্কার, এটি (সাধারণত) দ্রুত এবং এটি কোনও বস্তুর জন্য কাজ করে। এই অ্যাপ্লিকেশনটির জন্য এই পদ্ধতিটি ব্যবহার করার কোনও খারাপ দিক নেই।

পদ্ধতি 5 পদ্ধতি 4 তে একটি সাম্প্রতিক চিহ্ন - অ্যারেটিকে একটি ভেক্টরে অনুলিপি করুন এবং তারপরে এটি যুক্ত করুন। ভাল বিকল্প - সাধারণত দ্রুত-ইশ এবং পরিষ্কার।

অবশেষে, আপনি সচেতন যে আপনি অ্যারের জায়গায় ভেক্টর ব্যবহার করতে পারেন, তাই না? এমনকি যখন কোনও ফাংশন সি-স্টাইলের অ্যারেগুলি প্রত্যাশা করে আপনি ভেক্টরগুলি ব্যবহার করতে পারেন:

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

আশা করি সেখানকার কাউকে সাহায্য করবে!


6
আপনি নিরাপদে & বহনযোগ্যভাবে "& ডেটাআরাই [ডেটাআরাইসাইজ]" উল্লেখ করতে পারবেন না - এটি একটি অতীত-শেষ পয়েন্টার / পুনরাবৃত্তিকে ডিফার করছে। পরিবর্তে, আপনি পয়েন্টারটি প্রথমে ডিফারেন্স না করেই ডেটাআরয়ে + ডেটাআরাই সাইজ বলতে পারেন।
ড্রयू হল

2
@ ড্রু: হ্যাঁ, আপনি কমপক্ষে সিতে পারেন এটি সংজ্ঞায়িত করা হয় যা &exprমূল্যায়ন করে না expr, এটি কেবল এটির ঠিকানা গণনা করে। আর পয়েন্টার এক শেষ উপাদান গত পুরোপুরি বৈধ, অত্যধিক।
রোল্যান্ড ইলিগ

2
আপনি কি পদ্ধতিটি 4 দিয়ে 2 করার চেষ্টা করেছেন? যেমন serোকানোর আগে স্থান সংরক্ষণ করা। দেখে মনে হচ্ছে যদি ডেটার আকার বড় হয় তবে একাধিক সন্নিবেশগুলির জন্য একাধিক পুনঃনির্ধারণের প্রয়োজন হবে। যেহেতু আমরা আকারটি একটি অগ্রাধিকার জানি, সন্নিবেশ করার আগে আমরা পুনরায় স্থানটি করতে পারি।
জর্জি লিটাও

2
@ ম্যাটিটি 5 পদ্ধতির বিন্দুটি কী? কেন ডেটা এর মধ্যবর্তী কপি তৈরি?
Ruslan

2
আমি ব্যক্তিগতভাবে পয়েন্টারগুলিতে স্বয়ংক্রিয়ভাবে ক্ষয়কারী অ্যারে থেকে লাভ করতে চাই: dataVec.insert(dataVec.end(), dataArray, dataArray + dataArraySize);- আমার কাছে আরও পরিষ্কার appears পদ্ধতি 5 থেকে কোনও কিছুই অর্জন করা যায় না, কেবল বেশ অদক্ষ মনে হয় - যদি না কম্পাইলার আবার ভেক্টরটিকে আবার অনুকূল করতে সক্ষম না করে।
একনকাগুয়া

37

যদি আপনি যা করছেন সবই যদি বিদ্যমান ডেটাটি প্রতিস্থাপন করে তবে আপনি এটি করতে পারেন

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

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

1
বুঝতে সহজ এবং অবশ্যই দ্রুততম সমাধান (এটি কেবল পর্দার পিছনে একটি স্মৃতিবিজড়িত)।
ডন স্কট

ডেটা.সাইন্টের চেয়ে ডিটা.সাইনগ্যান কি দ্রুত?
জিম


10

যেহেতু আমি কেবল নিজের উত্তরটি সম্পাদনা করতে পারি, তাই আমি আমার প্রশ্নের অন্যান্য উত্তরগুলি থেকে একটি সম্মিলিত উত্তর দিতে যাচ্ছি। আপনারা যারা উত্তর দিয়েছেন সবাইকে ধন্যবাদ।

এসটিডি :: অনুলিপি ব্যবহার করে , এটি এখনও পটভূমিতে পুনরাবৃত্তি করে তবে আপনার কোডটি টাইপ করতে হবে না।

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

নিয়মিত মেমকি ব্যবহার করা হচ্ছে । এটি সম্ভবত প্রাথমিক তথ্য প্রকারের (যেমন ইন্ট্রি) জন্য সবচেয়ে বেশি ব্যবহৃত হয় তবে স্ট্রাক্ট বা ক্লাসের আরও জটিল অ্যারেগুলির জন্য নয়।

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));

আমি এই পদ্ধতির সুপারিশ করতে যাচ্ছি।
মিমোকনি

আপনি যদি আগে সময়ের আকারটি জানেন, এবং ব্যাক_ইনসেটরটি ব্যবহার না করেন তবে আপনার ভেক্টরটিকে সামনের দিকে পুনরায় আকার দেওয়া আরও দক্ষ efficient
luke

আপনি আমার_ডাটা.রিজার যুক্ত করতে পারেন (আকার)
ডেভিড

নোট করুন যে অভ্যন্তরীণভাবে এটি ঠিক তাই করছে যা আপনি এড়াতে চান বলে মনে হয়। এটি বিটগুলি অনুলিপি করছে না, এটি কেবল লুপিং এবং পুশ_ব্যাক () কল করছে। আমার ধারণা আপনি কেবল কোড টাইপ করা এড়াতে চেয়েছিলেন?
মিমোকনি

1
Wjy ডেটা অনুলিপি করতে ভেক্টর কনস্ট্রাক্টর ব্যবহার করবেন না?
মার্টিন ইয়র্ক

3

আমি বলি স্মৃতি এড়ানো পয়েন্টার অপারেশনগুলির সাথে ঝামেলা করার কোনও কারণ নেই যদি না আপনার সত্যিই দরকার হয়। এছাড়াও, এটি কেবল পিওডির ধরণের (ইন্টের মতো) জন্য কাজ করবে তবে আপনি যদি এমন ধরণের নির্মাণের প্রয়োজন হয় তবে তা ব্যর্থ হয়।


8
সম্ভবত এটি অন্য উত্তরগুলির একটিতে একটি মন্তব্য হওয়া উচিত, কারণ আপনি আসলে কোনও সমাধানের প্রস্তাব দেন না।
ফাইনুল

3
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 :-)

2
যতক্ষণ এই কোড স্নিপেট স্বাগত, এবং কিছু সাহায্য প্রদান করতে পারে, এটা হবে ব্যাপকভাবে উন্নত যদি এটা একটি ব্যাখ্যা অন্তর্ভুক্ত এর কিভাবে এবং কেন এই সমাধান সমস্যা। মনে রাখবেন যে আপনি ভবিষ্যতে পাঠকদের জন্য প্রশ্নের উত্তর দিচ্ছেন, কেবল এখনই জিজ্ঞাসা করা ব্যক্তি নয়! দয়া করে ব্যাখ্যা যুক্ত করতে আপনার উত্তর সম্পাদনা করুন, এবং কোন সীমাবদ্ধতা এবং অনুমানগুলি প্রযোজ্য তা একটি ইঙ্গিত দিন।
টবি স্পিড

4
দাঁড়াও, কী myints?
mavavilj

2

তবুও অন্য একটি উত্তর, যেহেতু ব্যক্তিটি বলেছিল "আমার ফাংশনটি কতবার ডাকা হবে তা আমি জানি না", তাই আপনি ভেক্টরের সন্নিবেশ পদ্ধতিটি ভেক্টরের শেষে মানগুলির অ্যারে যুক্ত করতে ব্যবহার করতে পারেন:

vector<int> x;

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

আমি এই উপায়টি পছন্দ করি কারণ ভেক্টরের প্রয়োগটি পুনরাবৃত্তকারী টাইপ এবং টাইপের উপর ভিত্তি করে মান সন্নিবেশ করার সর্বোত্তম পদ্ধতির জন্য অনুকূল করতে সক্ষম হওয়া উচিত। আপনি কিছুটা স্টিলের প্রয়োগের উপর জবাব দিচ্ছেন।

আপনার যদি দ্রুততম গতির গ্যারান্টি দেওয়া দরকার এবং আপনি জানেন যে আপনার প্রকারটি একটি পিওডি টাইপ হয় তবে আমি থমাসের উত্তরে পুনরায় আকার দেওয়ার পদ্ধতিটি সুপারিশ করব:

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

1

উপরে উপস্থাপিত পদ্ধতিগুলি ছাড়াও, আপনার ভেক্টরটিতে পর্যাপ্ত উপাদান রয়েছে কিনা তা নিশ্চিত করার জন্য আপনাকে অবশ্যই std :: Vector.reserve (), std :: Vector.resize () ব্যবহার করুন বা আকারে ভেক্টরটি তৈরি করতে হবে তা নিশ্চিত করতে হবে এটি আপনার তথ্য রাখা। যদি তা না হয় তবে আপনি স্মৃতিশক্তি নষ্ট করবেন। এটি স্ট্যান্ড :: কপি () বা মেমকি () এর ক্ষেত্রে সত্য।

এটি ভেক্টর.পুশ_ব্যাক () ব্যবহার করার কারণ, আপনি ভেক্টরের শেষটি লিখতে পারবেন না।


আপনি যদি কোনও ব্যাক_ইনসেটর ব্যবহার করে থাকেন তবে আপনার যে ভেক্টরটি অনুলিপি করছেন তার প্রাক-সংরক্ষণের দরকার নেই। back_inserter একটি পুশ_ব্যাক () করে।
জন ডিবলিং

0

ধরে নিচ্ছি আপনি ভেক্টরের আইটেমটি কত বড় তা জানেন:

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


এটি স্ট্যান্ড :: ভেক্টর বাস্তবায়নের উপর নির্ভর করে না?
ReaperUnreal

এটা কি সাংঘাতিক! আপনি দু'বার অ্যারে পূরণ করছেন, একটি '0 এর সাথে, তারপরে যথাযথ মান সহ। কেবলমাত্র: স্টডি :: ভেক্টর <মিন্ট> মাইআর্রে (উত্স, উত্স + আইটেম_কাউন্ট); এবং মেমকিটি তৈরি করতে আপনার সংকলককে বিশ্বাস করুন!
ক্রিস জেফারসন

__Memcpy_int_aligned উত্পাদন করতে আপনার সংকলককে বিশ্বাস করুন; এটি আরও দ্রুত হওয়া উচিত
এমএসএলটাররা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.