সি ++ 11 এর 'অটো' ব্যবহার কি পারফরম্যান্সকে উন্নত করতে পারে?


230

আমি দেখতে পাচ্ছি কেন autoসি ++ 11 টাইপটি সঠিকতা এবং রক্ষণাবেক্ষণযোগ্যতা উন্নত করে। আমি পড়েছি যে এটি পারফরম্যান্সকেও উন্নত করতে পারে ( প্রায় সবসময় অটো দ্বারা হার্ব সুটার), তবে আমি একটি ভাল ব্যাখ্যা মিস করছি।

  • কীভাবে autoপারফরম্যান্স উন্নতি করতে পারে?
  • কেউ কি উদাহরণ দিতে পারে?

5
দেখুন herbsutter.com/2013/06/13/… যা দুর্ঘটনাজনিত অন্তর্নিহিত রূপান্তরগুলি এড়ানো সম্পর্কে কথা বলে, যেমন গ্যাজেট থেকে উইজেট পর্যন্ত। এটি কোনও সাধারণ সমস্যা নয়।
জোনাথন ওয়াকলি

42
আপনি কি পারফরম্যান্সের উন্নতি হিসাবে "অনিচ্ছাকৃতভাবে হতাশার কম সম্ভাবনা তৈরি করেন"?
5gon12eder

1
কেবল ভবিষ্যতে কোড
সাফাইয়ের পারফরম্যান্স

আমাদের একটি সংক্ষিপ্ত উত্তর প্রয়োজন: না আপনি ভাল থাকলে। এটি 'নুবিশ' ভুল আটকাতে পারে। সি ++ এর একটি শিখনের বক্ররেখা রয়েছে যা তাদের সমস্ত লোকদের হত্যা করে যারা সর্বোপরি এটি তৈরি করে না।
অ্যালেক টিপ

উত্তর:


309

autoনিরব অন্তর্নিহিত রূপান্তরগুলি এড়িয়ে পারফরম্যান্সে সহায়তা করতে পারে । আমি উদাহরণস্বরূপ আকর্ষণীয় মনে করি যা নিম্নলিখিত।

std::map<Key, Val> m;
// ...

for (std::pair<Key, Val> const& item : m) {
    // do stuff
}

বাগটি দেখুন? আমরা এখানে রয়েছি, ভেবেছি আমরা মানচিত্রের প্রতি আইটেমটি মার্জিতভাবে নিচ্ছি এবং রেফারেন্সের জন্য এক্সপ্রেশনটি ব্যবহার করে আমাদের উদ্দেশ্যটি পরিষ্কার করে দিচ্ছি, তবে বাস্তবে আমরা প্রতিটি উপাদান নকল করছি । এ কারণে যে std::map<Key, Val>::value_typeহয় std::pair<const Key, Val>না std::pair<Key, Val>। সুতরাং, যখন আমাদের (অন্তর্নিহিত) থাকে:

std::pair<Key, Val> const& item = *iter;

কোনও বিদ্যমান অবজেক্টের রেফারেন্স নেওয়ার পরিবর্তে এটিকে রেখে যাওয়ার জন্য, আমাদের একটি ধরণের রূপান্তর করতে হবে। যতক্ষণ না কোনও অন্তর্নিহিত রূপান্তর উপলব্ধ থাকে ততক্ষণ আপনি আলাদা ধরণের কোনও অবজেক্টের (বা অস্থায়ী) রেফারেন্স নিতে পারবেন:

int const& i = 2.0; // perfectly OK

টাইপ রূপান্তর একই কারণে আপনি যদি একটি রূপান্তর করতে পারেন জন্য একটি অনুমতি অন্তর্নিহিত রূপান্তর হয় const Keyএকটি থেকে Key, কিন্তু আমরা অর্ডার যে জন্য অনুমতি নতুন ধরনের একটি অস্থায়ী গঠন করা হবে। সুতরাং, কার্যকরভাবে আমাদের লুপটি করে:

std::pair<Key, Val> __tmp = *iter;       // construct a temporary of the correct type
std::pair<Key, Val> const& item = __tmp; // then, take a reference to it

(অবশ্যই, আসলে কোনও __tmpবস্তু নেই, এটি কেবল উদাহরণের জন্য রয়েছে, বাস্তবে নামবিহীন অস্থায়ী itemতার জীবনকালের জন্য আবদ্ধ )।

কেবল এতে পরিবর্তন করা হচ্ছে:

for (auto const& item : m) {
    // do stuff
}

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


19
@ ব্যারি আপনি কি ব্যাখ্যা করতে পারেন যে সংকলকটি কেন একটি std::pair<const Key, Val> const &হিসাবে গণ্য করার চেষ্টা করার অভিযোগের পরিবর্তে আনন্দের সাথে অনুলিপিগুলি তৈরি করবে std::pair<Key, Val> const &? C ++ 11-এ নতুন, কীভাবে পরিসীমা হবে এবং এটি কীভাবে autoখেলবে তা নিশ্চিত নয় ।
আগপ

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

@ ব্যারি আমি আপনাকে পেয়েছি, তবে সমস্যাটি হ'ল তখন কোনও উত্তর নেই যা autoসেই বৃদ্ধি কর্মক্ষমতাটি ব্যবহার করার সমস্ত কারণকে কভার করে। তাই আমি এটি নীচে আমার নিজের কথায় লিখে রাখব।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

38
আমি এখনও মনে করি না যে এটি " autoপারফরম্যান্স উন্নত করে" তার প্রমাণ । এটি কেবলমাত্র একটি উদাহরণ যা " autoপ্রোগ্রামার ভুলগুলি প্রতিরোধে সহায়তা করে যা কার্য সম্পাদন করে।" আমি জমা দিচ্ছি যে উভয়ের মধ্যে একটি সূক্ষ্ম তবুও গুরুত্বপূর্ণ পার্থক্য রয়েছে। তবুও, +1।
কক্ষপথের হালকাত্বের রেস

70

যেহেতু autoপ্রারম্ভিক প্রকাশের ধরণকে হ্রাস করে, এতে কোনও ধরণের রূপান্তর জড়িত নেই। টেম্প্লেটেড অ্যালগরিদমের সাথে সংযুক্ত, এর অর্থ হল যে আপনি নিজের চেয়ে নিজেকে আলাদা করে তৈরি করার চেয়ে আরও বেশি সরাসরি গণনা পেতে পারেন - বিশেষত যখন আপনি যার মত প্রকাশের সাথে কথা বলছেন যার নাম আপনি দিতে পারেন না!

(আব) ব্যবহার করে একটি সাধারণ উদাহরণ এসেছে std::function:

std::function<bool(T, T)> cmp1 = std::bind(f, _2, 10, _1);  // bad
auto cmp2 = std::bind(f, _2, 10, _1);                       // good
auto cmp3 = [](T a, T b){ return f(b, 10, a); };            // also good

std::stable_partition(begin(x), end(x), cmp?);

এর সাথে cmp2এবং cmp3সম্পূর্ণ অ্যালগরিদম তুলনা কলকে ইনলাইন করতে পারে, আপনি যদি কোনও std::functionবস্তুটি তৈরি করেন তবে কলটি কেবল ইনলাইন করা যায় না, তবে আপনাকে ফাংশন র‌্যাপারের টাইপ-মোছা অভ্যন্তরের পলিমারফিক লুকও যেতে হবে।

এই থিমটির অন্য একটি রূপটি আপনি বলতে পারেন:

auto && f = MakeAThing();

এটি সর্বদা একটি রেফারেন্স, ফাংশন কল এক্সপ্রেশনটির মানের সাথে আবদ্ধ এবং কখনও কোনও অতিরিক্ত অবজেক্ট তৈরি করে না। যদি আপনি প্রত্যাশিত মানটির ধরণটি না জানতেন তবে আপনাকে এমন কোনও কিছুর মাধ্যমে কোনও নতুন অবজেক্ট (সম্ভবত একটি অস্থায়ী হিসাবে) তৈরি করতে বাধ্য করা যেতে পারে T && f = MakeAThing()। (তদুপরি, auto &&এমনকি রিটার্নের ধরণের চলনযোগ্য না থাকা এবং রিটার্নের মানটি মূল্য নির্ধারণের সময়ও কাজ করে))


সুতরাং এটি "ধরণের ক্ষয় এড়ান" ব্যবহারের কারণ auto। আপনার অন্যান্য রূপটি হ'ল "দুর্ঘটনাজনিত অনুলিপিগুলি এড়ানো", তবে শোভাময় প্রয়োজন; কেন autoআপনি কেবল সেখানে টাইপ টাইপ করার গতি দেন? (আমি মনে করি উত্তরটি "আপনি টাইপটি ভুল পেয়েছেন, এবং এটি নিঃশব্দে রূপান্তরিত হয়") কোনটি এটি ব্যারির উত্তরটির একটি কম-সুস্পষ্ট ব্যাখ্যাযোগ্য উদাহরণ করে, না? উদাহরণস্বরূপ, দুটি বেসিক কেস রয়েছে: টাইপ ক্ষয় এড়ানোর জন্য অটো এবং দুর্ঘটনাক্রমে রূপান্তরিত নীরব প্রকারের ত্রুটিগুলি এড়ানোর জন্য অটো এবং উভয়টিরই সময় ব্যয় হয়।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

2
"কেবল কলটি অন্তর্ভুক্ত করা যাবে না" - তবে কেন? আপনি কি এটি বলতে যে নীতি কিছু প্রতিরোধ করে কল devirtualized হচ্ছে ডেটা যদি প্রাসঙ্গিক বিশেষায়িত প্রবাহিত পর বিশ্লেষণ করতে std::bind, std::functionএবং std::stable_partitionসব inlined করা হয়েছে? বা ঠিক যে অনুশীলনে কোনও সি ++ সংকলক গণ্ডগোল বাছাইয়ের জন্য যথেষ্ট আগ্রাসীভাবে ইনলাইন করবে না?
স্টিভ জেসোপ

@ স্টিভ জেসোপ: বেশিরভাগ পরে - আপনি std::functionকনস্ট্রাক্টরের মাধ্যমে যাওয়ার পরে , প্রকৃত কলটি বিশেষত ক্ষুদ্র-ফাংশন অপ্টিমাইজেশনের মাধ্যমে দেখতে খুব জটিল হয়ে উঠবে (যাতে আপনি প্রকৃতপক্ষে ডেভার্টুয়ালাইজেশন চান না)। অবশ্যই নীতিগতভাবে সমস্ত কিছু হ'ল ...
কেরেরেক এসবি

41

দুটি বিভাগ আছে।

autoপ্রকারের ক্ষয় এড়ানো যায়। এখানে অবিচ্ছেদ্য ধরণের (ল্যাম্বডাসের মতো), এবং প্রায় অপ্রয়োজনীয় প্রকারগুলি (যেমন পণ্যগুলির মতো std::bindবা অন্যান্য প্রকাশ-টেমপ্লেটের ফলাফল )।

ছাড়া auto, আপনি ডেটা মুছে টাইপের মতো শেষ করে ফেলবেন std::function। প্রকার মুছে ফেলার খরচ রয়েছে।

std::function<void()> task1 = []{std::cout << "hello";};
auto task2 = []{std::cout << " world\n";};

task1টাইপ ইরেজর ওভারহেড রয়েছে - একটি সম্ভাব্য গাদা বরাদ্দ, এটি অন্তর্ভুক্ত করতে অসুবিধা এবং ভার্চুয়াল ফাংশন টেবিলের অনুরোধ ওভারহেড। task2কিছুই নেই। Lambdas প্রয়োজন স্বয়ংক্রিয় বা ছাড়া টাইপ ইরেজিওর দোকান থেকে টাইপ সিদ্ধান্তগ্রহণ অন্যান্য ধরনের; অন্যান্য ধরণেরগুলি এত জটিল হতে পারে যে অনুশীলনে কেবল এটির প্রয়োজন।

দ্বিতীয়ত, আপনি টাইপগুলি ভুল পেতে পারেন। কিছু ক্ষেত্রে, ভুল ধরণের আপাতদৃষ্টিতে পুরোপুরি কাজ করবে, তবে একটি অনুলিপি তৈরি করবে।

Foo const& f = expression();

সংকলন করবে যদি expression()ফেরত দেয় Bar const&বা Barএমনকি Bar&, কোথা Fooথেকে তৈরি করা যায় Bar। একটি অস্থায়ী তৈরি করা Fooহবে, তারপরে আবদ্ধ fএবং তার জীবনকাল fদূরে না যাওয়া পর্যন্ত বাড়ানো হবে ।

প্রোগ্রামারটি Bar const& fসেখানে একটি অনুলিপি তৈরি করার উদ্দেশ্যে বোঝাতে চেয়েছিল এবং নাও হতে পারে , তবে একটি অনুলিপি নির্বিশেষে তৈরি করা হবে।

সর্বাধিক সাধারণ উদাহরণ প্রকার *std::map<A,B>::const_iterator, যা std::pair<A const, B> const&নয় std::pair<A,B> const&তবে ত্রুটিটি এমন এক শ্রেণীর ত্রুটি যা নিঃশব্দে কর্মক্ষমতা ব্যয় করে। আপনি একটি std::pair<A, B>থেকে একটি নির্মাণ করতে পারেন std::pair<const A, B>। (মানচিত্রের কীটি কনস্ট, কারণ এটি সম্পাদনা করা একটি খারাপ ধারণা)

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


9

বিদ্যমান তিনটি উত্তর উদাহরণ দেয় যেখানে ব্যবহার autoকরে এটি "অবিচ্ছিন্নভাবে হতাশার সম্ভাবনা কম করে" কার্যকরভাবে এটিকে "পারফরম্যান্স উন্নতি " করে তোলে

মুদ্রার একটি ফ্লিপ দিক রয়েছে। ব্যবহার autoবস্তু আছে অপারেটার যে মৌলিক বস্তুর ফেরত না ভুল (এখনও compilable এবং runable) কোড ঘটাতে পারে না। উদাহরণস্বরূপ, এই প্রশ্নটি জিজ্ঞাসা করে যে কীভাবে autoইগেন লাইব্রেরিটি ব্যবহার করা হয়েছে, অর্থাত নীচের লাইনগুলি ব্যবহার করে বিভিন্ন (ভুল) ফলাফল দেওয়া হয়েছিল

const auto    resAuto    = Ha + Vector3(0.,0.,j * 2.567);
const Vector3 resVector3 = Ha + Vector3(0.,0.,j * 2.567);

std::cout << "resAuto = " << resAuto <<std::endl;
std::cout << "resVector3 = " << resVector3 <<std::endl;

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

যদিও পারফরম্যান্স এখানে খুব বেশি প্রভাবিত হয়নি, autoঅনিচ্ছাকৃত হতাশা এড়ানোর জন্য ব্যবহারকে অকালীন অপটিমাইজেশন বা অন্তত ভুল হিসাবে চিহ্নিত করা যেতে পারে;)।


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