সিবেগিন / সেন্টের পেছনের কারণ কী?


188

আমি ভাবছি কেন cbeginএবং কেন cendসি ++ 11 এ চালু হয়েছিল?

মামলা কি কি যখন এই পদ্ধতি কলিং const overloads থেকে একটি পার্থক্য তোলে beginএবং end?

উত্তর:


227

এটা বেশ সহজ। বলুন আমার কাছে ভেক্টর রয়েছে:

std::vector<int> vec;

আমি কিছু তথ্য দিয়ে এটি পূরণ। তারপরে আমি এটিতে কিছু পুনরাবৃত্তি পেতে চাই। তাদের কাছাকাছি যেতে পারে। হতে পারে std::for_each:

std::for_each(vec.begin(), vec.end(), SomeFunctor());

C ++ 03 এ, প্যারামিটারটি পাওয়ার সাথে সাথে এটি সংশোধনSomeFunctor করতে সক্ষম হয়েছিল । অবশ্যই, মান দ্বারা বা তার পরামিতি নিতে পারে , তবে এটি নিশ্চিত করার কোনও উপায় নেই। এর মতো নির্বোধ কিছু না করে:SomeFunctorconst&

const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());

এখন, আমরা পরিচয় করিয়ে দেই cbegin/cend:

std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());

এখন, আমাদের সিনট্যাকটিক আশ্বাস রয়েছে যা SomeFunctorভেক্টরের উপাদানগুলিকে সংশোধন করতে পারে না (অবশ্যই কোনও কনস্ট-কাস্ট ছাড়াই)। আমরা স্পষ্টতই const_iteratorএস পাই , এবং সেইজন্য SomeFunctor::operator()তাদের সাথে ডাকা হবে const int &। যদি এটি এর পরামিতি হিসাবে নেয় তবে int &সি ++ একটি সংকলক ত্রুটি জারি করবে।


সি ++ 17 এই সমস্যার একটি আরো মার্জিত সমাধান আছে: std::as_const। ভাল, পরিসীমা ভিত্তিক ব্যবহার করার সময় কমপক্ষে এটি মার্জিত for:

for(auto &item : std::as_const(vec))

এটি কেবল const&যে বস্তুটি সরবরাহ করা হয় তাতে ফিরে আসে ।


1
আমি ভেবেছিলাম নতুন প্রোটোকলটি vec.cbegin () এর পরিবর্তে cbegin (vec) ছিল।
কাজ ড্রাগন

20
@ কাজ: std::cbegin/cendযেভাবে std::begin/std::endঅস্তিত্ব রয়েছে সেভাবে কোনও ফ্রি ফাংশন নেই। এটি কমিটি দ্বারা একটি তদারকি ছিল। যদি এই ফাংশনগুলি উপস্থিত থাকে, তবে এটি সাধারণত তাদের ব্যবহার করার উপায় ছিল।
নিকল বোলাস

20
স্পষ্টতই, std::cbegin/cendসি ++ 14 এ যুক্ত করা হবে। দেখুন en.cppreferences.com/w/cpp/iterator/begin
আদি

8
@ নিকলবোলাস for(auto &item : std::as_const(vec))সমান for(const auto &item : vec)?
luizfls

8
@ লুইজফ্লস হ্যাঁ আপনার কোড বলে constরেফারেন্সটি রেখে আইটেমটি পরিবর্তন করা হবে না । নিকলের কনটেইনারটি কনস্ট হিসাবে দেখায়, তাই রেফারেন্সটি autoহ্রাস করে const। আইএমও auto const& itemসহজ এবং পরিষ্কার। std::as_const()এখানে কেন ভাল তা স্পষ্ট নয় ; আমি দেখতে পেলাম constযে জেনেরিক কোডটি নন-এমন কিছু পাস করার সময় এটি দরকারী হবে যেখানে আমরা যে ধরণের ব্যবহার করতে পারি তা নিয়ন্ত্রণ করতে পারি না, তবে পরিসীমা সহ for, আমরা এটি করতে পারি, সুতরাং এটি কেবল আমার কাছে বাড়তি আওয়াজ বলে মনে হচ্ছে।
আন্ডারস্কোর_

66

নিকোল বোলাস তার উত্তরে যা বলেছিল তার বাইরে নতুন autoকীওয়ার্ডটি বিবেচনা করুন :

auto iterator = container.begin();

সাথে auto, এটি নিশ্চিত করার উপায় নেই যে কোনও begin()ধ্রুবক ধারক রেফারেন্সের জন্য একটি ধ্রুবক অপারেটর ফিরে আসে। সুতরাং এখন আপনি কি:

auto const_iterator = container.cbegin();

2
@allyourcode: সাহায্য করে না। সংকলকটির const_iteratorকাছে কেবল অন্য শনাক্তকারী। কোনও সংস্করণই সাধারণ সদস্য টাইপডেফসের চেহারা decltype(container)::iteratorবা ব্যবহার করে না decltype(container)::const_iterator
aschepler

2
@ এস্পেল্পার আমি আপনার দ্বিতীয় বাক্যটি বুঝতে পারি না তবে আমার মনে হয় আপনি আমার প্রশ্নের "অটো" এর সামনে "কনস্ট" মিস করেছেন। অটো যা-ই আসুক না কেন, মনে হয় কনস্টেটারের কনস্টেট হওয়া উচিত।
অ্যালিউরকোড

26
@allyourcode: এটি আপনাকে এমন একটি পুনরুক্তি দেবে যা ধ্রুবক, তবে এটি একটি পুনরুক্তকারী থেকে ধ্রুবক ডেটা থেকে খুব আলাদা।
aschapler

2
নিশ্চিত করুন যে আপনি পেতে একটি সহজ উপায় নেই const_iteratorসঙ্গে autoলিখুন নামক একটি অক্জিলিয়ারী ফাংশন টেমপ্লেট: make_constঅবজেক্ট যুক্তি যোগ্যতা।
কলম্বো 26'15

17
সম্ভবত আমি আর সি ++ মানসিকতায় নেই, তবে "একটি সহজ উপায়" এবং "একটি সহায়ক ফাংশন টেম্পলেট লিখুন" এর ধারণার মধ্যে কোনও সংযোগ দেখতে পাচ্ছি না। ;)
স্টিফান মাজেউস্কি

15

এটি ব্যবহারিক ব্যবহারের ক্ষেত্র হিসাবে গ্রহণ করুন

void SomeClass::f(const vector<int>& a) {
  auto it = someNonConstMemberVector.begin();
  ...
  it = a.begin();
  ...
}

অ্যাসাইনমেন্ট ব্যর্থ হয়েছে কারণ itএকটি ননকনস্ট পুনরুক্তিকারী। আপনি যদি প্রাথমিকভাবে সিবেগিন ব্যবহার করেন তবে পুনরাবৃত্তির সঠিক টাইপটি থাকতে পারে।


8

Http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1674.pdf থেকে :

যাতে কোনও প্রোগ্রামার সরাসরি কোনও কনস্ট্যান্ট কনটেইনার থেকেও কনস্টেটিটর পেতে পারে

তারা এই উদাহরণ দিয়েছেন

vector<MyType> v;

// fill v ...
typedef vector<MyType>::iterator iter;
for( iter it = v.begin(); it != v.end(); ++it ) {
    // use *it ...
}

যাইহোক, যখন কোনও ধারক ট্র্যাভারসাল কেবলমাত্র পরিদর্শন করার উদ্দেশ্যে করা হয়, তখন কনস্টাইলারকে কনস্ট-শোধনের লঙ্ঘনের জন্য নির্ধারিত করার জন্য কনস্টেটার ব্যবহার করা সাধারণত পছন্দসই অনুশীলন is

নোট কাজ কাগজের এছাড়াও অ্যাডাপ্টারের টেমপ্লেট উল্লেখ, যে এখন যেমন চূড়ান্ত হয়েছে std::begin()এবং std::end()এবং যে এছাড়াও নেটিভ অ্যারে সঙ্গে কাজ করে। সম্পর্কিত std::cbegin()এবং std::cend()কৌতূহলীভাবে এই সময় হিসাবে নিখোঁজ, কিন্তু তারা এছাড়াও যুক্ত হতে পারে।


5

এই প্রশ্নটিতে কেবল হোঁচট খেয়েছে ... আমি জানি এটির উত্তরের উত্তর দেওয়া হয়েছে এবং এটি কেবল একটি পাশের নোড ...

auto const it = container.begin() তখন অন্যরকম auto it = container.cbegin()

পার্থক্যের জন্য int[5](পয়েন্টার ব্যবহার করে, যা আমি জানি যে শুরুর পদ্ধতিটি নেই তবে পার্থক্যটি ভালভাবে দেখায় ... তবে সি ++ 14 এ কাজ করবে std::cbegin()এবং std::cend()এটি এখানে যখন মূলত কোনটি ব্যবহার করা উচিত) ...

int numbers = array[7];
const auto it = begin(numbers); // type is int* const -> pointer is const
auto it = cbegin(numbers);      // type is int const* -> value is const

2

iteratorএবং const_iteratorউত্তরাধিকারের সম্পর্ক রয়েছে এবং অন্য ধরণের সাথে তুলনা করা বা নির্ধারিত হলে একটি অন্তর্নিহিত রূপান্তর ঘটে।

class T {} MyT1, MyT2, MyT3;
std::vector<T> MyVector = {MyT1, MyT2, MyT3};
for (std::vector<T>::const_iterator it=MyVector.begin(); it!=MyVector.end(); ++it)
{
    // ...
}

ব্যবহার cbegin()এবং cend()এই ক্ষেত্রে কর্মক্ষমতা বৃদ্ধি করবে।

for (std::vector<T>::const_iterator it=MyVector.cbegin(); it!=MyVector.cend(); ++it)
{
    // ...
}

আমার অনুধাবন করতে আমার কিছুটা সময় লেগেছিল যে আপনি বোঝাতে পেরেছেন যে পুনরাবৃত্তি আরম্ভের সাথে তুলনা করার সময় রূপান্তর এড়ানোর মাধ্যমে পারফরম্যান্স বাঁচানো হয়েছে, জনপ্রিয় পৌরাণিক কাহিনী নয় যে constএর মূল উপকারিতা হল কর্মক্ষমতা (যা এটি নয়: এটি শব্দার্থগতভাবে সঠিক এবং নিরাপদ কোড)। তবে, আপনার একটি বক্তব্য থাকার সময়, (এ) autoএটিকে একটি নন-ইস্যু করে তোলে; (খ) পারফরম্যান্স সম্পর্কে কথা বলতে গিয়ে, আপনার এখানে করা উচিত ছিল এমন একটি প্রধান জিনিসটি মিস করেছেন: endপুনরুক্তির forপরিবর্তে একটি নতুন অনুলিপি না পাওয়ার পরিবর্তে পুনরুক্তিটির কপিটি লুপের ইনি-শর্তে ঘোষণা করে এবং তার সাথে তুলনা করুন প্রতিটি পুনরাবৃত্তির জন্য মান। এটি আপনার বক্তব্যকে আরও ভাল করে তুলবে। : পি
আন্ডারস্কোর_

@ আসরস্কোর_ডি স্পষ্টরূপে আরও constভাল পারফরম্যান্স অর্জনে সহায়তা করতে পারে, constকীওয়ার্ডে নিজেই কিছু ম্যাজিকের কারণে নয়, কারণ সংকলক কিছু অপ্টিমাইজেশন সক্ষম করতে পারে যদি এটি জানে যে ডেটা সংশোধন করা হবে না, যা অন্যথায় সম্ভব হবে না। এর লাইভ উদাহরণের জন্য জেসন টার্নারের আলাপ থেকে এই বিটটি দেখুন ।
ব্রেইনপ্লট

@ ব্রেনপ্ল্লট আমি বলিনি যে এটি পারে না। আমি বলেছিলাম এটি এর মূল উপকার নয় এবং আমি মনে করি এটি অত্যধিক আকার ধারণ করে, যখন এর আসল সুবিধাটি শব্দার্থগতভাবে সঠিক এবং নিরাপদ কোড হয়।
আন্ডারস্কোর_ডে

হ্যাঁ, আমি তাতে একমত আমি কেবল এটি স্পষ্ট করে বলছিলাম যা const(প্রায় পরোক্ষভাবে) পারফরম্যান্স সুবিধার দিকে নিয়ে যেতে পারে; কেবল কেউ যদি এটি পড়ে তবে মনে করে " constউত্পন্ন কোডটি কোনওভাবেই প্রভাবিত না হলে আমি যুক্ত করে বিরক্ত করব না ", যা সত্য নয়।
ব্রেইনপ্লট 27'19

0

এটির সহজ, সিবেগিন একটি ধ্রুবক পুনরাবৃত্তি প্রদান করে যেখানে শুরু কেবলমাত্র একটি পুনরাবৃত্তিকে দেয়

আরও ভাল বোঝার জন্য এখানে দুটি পরিস্থিতি নেওয়া যায়

দৃশ্যপট 1 :

#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;

for (int i = 1; i < 6; ++i)
{
    /* code */
    v.push_back(i);
}

for(auto i = v.begin();i< v.end();i++){
    *i = *i + 5;
}

for (auto i = v.begin();i < v.end();i++){
    cout<<*i<<" ";
}

return 0;
}

এটি চলবে কারণ এখানে পুনরাবৃত্তিকারী আমি ধ্রুবক নয় এবং 5 দ্বারা বাড়ানো যেতে পারে

এখন আসুন সিবেগিন ব্যবহার করুন এবং এগুলি স্থির পুনরাবৃত্তির দৃশ্যের হিসাবে চিহ্নিত করুন - 2:

#include <iostream>
using namespace std;
#include <vector>
int main(int argc, char const *argv[])
{
std::vector<int> v;

for (int i = 1; i < 6; ++i)
{
    /* code */
    v.push_back(i);
}

for(auto i = v.cbegin();i< v.cend();i++){
    *i = *i + 5;
}

for (auto i = v.begin();i < v.end();i++){
    cout<<*i<<" ";
}

return 0;
}

এটি কাজ করে না, কারণ আপনি সিবিগিন এবং সেন্ট ব্যবহার করে মানটি আপডেট করতে পারবেন না যা ধ্রুবক পুনরাবৃত্তিকে ফেরত দেয়

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