কোডিং শৈলী চূড়ান্তভাবে বিষয়গত, এবং এটির থেকে যথেষ্ট পারফরম্যান্স সুবিধা আসার সম্ভাবনা খুব কম is তবে আমি এখানে যা বলব তা আপনি ইউনিফর্ম আরম্ভের উদার ব্যবহার থেকে লাভ করেছেন:
রিন্ডন্ড্যান্ট টাইপনেমগুলি হ্রাস করে
নিম্নোক্ত বিবেচনা কর:
vec3 GetValue()
{
return vec3(x, y, z);
}
আমাকে কেন vec3
দু'বার টাইপ করতে হবে ? সেখানে কি কোন বক্তব্য আছে? সংকলকটি ফাংশনটি কী ফিরিয়ে দেয় তা ভাল এবং ভাল জানেন। কেন আমি কেবল বলতে পারি না, "আমি এই মানগুলি দিয়ে যা ফিরিয়ে দেব তার কনস্ট্রাক্টরকে কল করুন এবং এটি ফিরিয়ে দেব?" অভিন্ন সূচনা সহ, আমি এটি করতে পারি:
vec3 GetValue()
{
return {x, y, z};
}
সবকিছু সচল.
এমনকি আরও ভাল ফাংশন আর্গুমেন্ট জন্য। এই বিবেচনা:
void DoSomething(const std::string &str);
DoSomething("A string.");
এটি কোনও টাইপনেম টাইপ না করেই কাজ করে, কারণ std::string
কীভাবে নিজেকে স্পষ্টভাবে তৈরি করতে হয় তা জানে const char*
। দারুণ. তবে সেই স্ট্রিংটি যদি আসে তবে র্যাপিডএক্সএমএল বলে। অথবা একটি লুয়া স্ট্রিং। অর্থাৎ, আসুন আমি বলি আমি আসলে স্ট্রিং আপ ফ্রন্টের দৈর্ঘ্য জানি know যে std::string
কনস্ট্রাক্টর একটি const char*
উইল নেয় তার স্ট্রিংয়ের দৈর্ঘ্য নিতে হবে যদি আমি কেবল একটি পাস করি const char*
।
স্পষ্টভাবে যদিও একটি দৈর্ঘ্য লাগে একটি ওভারলোড আছে। কিন্তু এটা ব্যবহার করার আমি এই কাজ করতে চাই: DoSomething(std::string(strValue, strLen))
। কেন সেখানে অতিরিক্ত টাইপনেম রয়েছে? সংকলকটি জানে যে প্রকারটি কী। ঠিক যেমন auto
, আমরা অতিরিক্ত টাইপনামগুলি এড়াতে পারি:
DoSomething({strValue, strLen});
এটা ঠিক কাজ করে। কোনও টাইপনেম নেই, কোলাহল নেই, কিছুই নেই। সংকলকটি তার কাজটি করে, কোডটি ছোট, এবং সকলেই খুশি।
মঞ্জুর, এখানে যুক্তি রয়েছে যে প্রথম সংস্করণ ( DoSomething(std::string(strValue, strLen))
) আরও সুগঠিত। এটি হ'ল স্পষ্টতই কী চলছে এবং কে কী করছে। কিছুটা হলেও সত্য; অভিন্ন সূচনা-ভিত্তিক কোডটি বোঝার জন্য ফাংশন প্রোটোটাইপটি দেখার প্রয়োজন। এটি একই কারণে কেন কেউ কেউ বলেন যে আপনার কখনই অ-নিরপেক্ষ রেফারেন্স দ্বারা প্যারামিটারগুলি পাস করা উচিত নয়: যাতে কোনও মান সংশোধন করা হচ্ছে তবে আপনি কল সাইটে দেখতে পারবেন।
তবে একই কথা বলা যেতে পারে auto
; আপনি কী পান তা জানার auto v = GetSomething();
জন্য সংজ্ঞাটি দেখার প্রয়োজন GetSomething
। এটি auto
একবার অ্যাক্সেস পেয়ে গেলে কাছাকাছি বেপরোয়া ত্যাগের সাথে ব্যবহার করা বন্ধ করে দেয় না । ব্যক্তিগতভাবে, আমি মনে করি এটি ব্যবহার করা ভাল হয়ে যাবে। বিশেষত একটি ভাল আইডিই সহ।
কখনই সর্বাধিক ভেক্সিং পার্স পাবেন না
এখানে কিছু কোড।
class Bar;
void Func()
{
int foo(Bar());
}
পপ কুইজ: কী foo
? আপনি যদি "একটি চলক" উত্তর দিয়ে থাকেন তবে আপনি ভুল। এটি আসলে কোনও ফাংশনের প্রোটোটাইপ যা এটির পরামিতি হিসাবে একটি ফাংশন নেয় যা একটি প্রদান করে Bar
এবং foo
ফাংশনটির রিটার্ন মানটি একটি ইনট হয়।
একে সি ++ এর "সর্বাধিক ভেক্সিং পার্স" বলা হয় কারণ এটি কোনও মানুষের পক্ষে একেবারেই কোনও ধারণা রাখে না। তবে দুঃখের সাথে সি ++ এর নিয়মগুলির প্রয়োজন: এটি সম্ভবত কোনও ফাংশন প্রোটোটাইপ হিসাবে ব্যাখ্যা করা যায়, তবে এটি হবে । সমস্যা হ'ল Bar()
; যে দুটি জিনিস এক হতে পারে। এটি একটি প্রকারের নাম হতে পারে Bar
যার অর্থ এটি একটি অস্থায়ী তৈরি করছে। অথবা এটি এমন কোনও ফাংশন হতে পারে যা কোনও প্যারামিটার নেয় না এবং একটি প্রদান করে Bar
।
ইউনিফর্ম সূচনাটি ফাংশন প্রোটোটাইপ হিসাবে ব্যাখ্যা করা যায় না:
class Bar;
void Func()
{
int foo{Bar{}};
}
Bar{}
সর্বদা একটি অস্থায়ী তৈরি করে। int foo{...}
সর্বদা একটি পরিবর্তনশীল তৈরি করে।
এমন অনেকগুলি ক্ষেত্রে রয়েছে যেখানে আপনি ব্যবহার করতে চান Typename()
তবে সি ++ এর পার্সিং বিধিগুলির কারণে সহজেই পারেন না। সাথে Typename{}
, কোনও দ্বিধা নেই।
না করার কারণগুলি
আপনি ছেড়ে দেওয়া একমাত্র আসল শক্তি হ'ল সংকীর্ণ। আপনি অভিন্ন ইনিশিয়ালাইজেশন সহ একটি বৃহত্তর সাথে একটি ছোট মান আরম্ভ করতে পারবেন না।
int val{5.2};
এটি সংকলন করবে না। আপনি এটি পুরানো ফ্যাশন সূচনা দিয়ে করতে পারেন, তবে অভিন্ন সূচনা নয়।
ইনিশিয়ালাইজার তালিকাগুলি আসলে কাজ করার জন্য এই অংশটি করা হয়েছিল। অন্যথায়, প্রারম্ভিক তালিকা তালিকার ধরণের ক্ষেত্রে প্রচুর অস্পষ্ট মামলা হবে।
অবশ্যই, কিছু যুক্তি দিতে পারে যে এই জাতীয় কোডটি সংকলন না করার যোগ্য ves আমি ব্যক্তিগতভাবে একমত হতে; সংকীর্ণতা খুব বিপজ্জনক এবং অপ্রীতিকর আচরণের দিকে পরিচালিত করতে পারে। সংকলক পর্যায়ে এই সমস্যাগুলি শুরু করা খুব সম্ভবত সেরা। খুব কমপক্ষে, সংকীর্ণ হওয়ার পরামর্শ দেয় যে কেউ কোড সম্পর্কে খুব বেশি চিন্তা করছেন না।
লক্ষ্য করুন যে সংকলকগণ সাধারণত আপনার এই সতর্কতার স্তরটি বেশি হলে এই ধরণের জিনিস সম্পর্কে আপনাকে সতর্ক করে দেবে। সুতরাং সত্যই, এই সমস্তটি হ'ল সতর্কতাটিকে একটি কার্যকর ত্রুটিতে পরিণত করে। কেউ কেউ বলতে পারে যে আপনার যাইহোক এটি করা উচিত;)
না করার আরও একটি কারণ রয়েছে:
std::vector<int> v{100};
এটি কি করে? এটি vector<int>
একশ ডিফল্ট-নির্মিত আইটেম সহ একটি তৈরি করতে পারে । বা এটি এমন vector<int>
1 টি আইটেম তৈরি করতে পারে যার মান 100
। উভয় তাত্ত্বিকভাবে সম্ভব।
বাস্তবে, এটি পরেরটি করে।
কেন? ইনিশিয়ালাইজার তালিকাগুলি অভিন্ন সূচনা হিসাবে একই সিনট্যাক্স ব্যবহার করে। সুতরাং অস্পষ্টতার ক্ষেত্রে কী করা উচিত তা ব্যাখ্যা করার জন্য কিছু বিধি থাকতে হবে। নিয়মটি বেশ সহজ: যদি সংকলক একটি ব্রেস-ইনিশিয়ালাইজড তালিকার সাহায্যে কোনও ইনিশিয়ালার তালিকা নির্মাণকারী ব্যবহার করতে পারে তবে তা হবে । যেহেতু vector<int>
একটি ইনিশিয়ালাইজার তালিকার কনস্ট্রাক্টর রয়েছে যা গ্রহণ করে initializer_list<int>
এবং {100 a একটি বৈধ হতে পারে initializer_list<int>
, সুতরাং এটি অবশ্যই হওয়া উচিত ।
সাইজিং কনস্ট্রাক্টর পেতে আপনার ()
পরিবর্তে অবশ্যই ব্যবহার করতে হবে {}
।
মনে রাখবেন যে এটি যদি এমন কোনও vector
কিছু হয় যা পূর্ণসংখ্যার সাথে রূপান্তরযোগ্য না হয় তবে এটি ঘটত না। একটি ইনিশিয়াল_লিস্ট সেই vector
ধরণের ইনিশিয়ালাইজার তালিকার কনস্ট্রাক্টরের সাথে খাপ খায় না , এবং তাই সংযোজকটি অন্য নির্মাণকারীদের থেকে বাছাই করতে পারে।