আমার কোথায় ম্যাক্রোগুলি পছন্দ করা উচিত এবং আমি কোথায় কনটেক্সট্রপ পছন্দ করব ? তারা কি মূলত এক নয়?
#define MAX_HEIGHT 720
বনাম
constexpr unsigned int max_height = 720;
আমার কোথায় ম্যাক্রোগুলি পছন্দ করা উচিত এবং আমি কোথায় কনটেক্সট্রপ পছন্দ করব ? তারা কি মূলত এক নয়?
#define MAX_HEIGHT 720
বনাম
constexpr unsigned int max_height = 720;
উত্তর:
তারা কি মূলত এক নয়?
না। কাছেও নয়।
আপনার ম্যাক্রোটি একটি intএবং আপনার constexpr unsignedএকটি unsignedব্যতীত গুরুত্বপূর্ণ পার্থক্য রয়েছে এবং ম্যাক্রোর কেবল একটি সুবিধা রয়েছে।
একটি ম্যাক্রো প্রিপ্রোসেসর দ্বারা সংজ্ঞায়িত করা হয় এবং প্রতিটি সময় কোডটি সহজেই প্রতিস্থাপিত হয়। প্রিপ্রোসেসর বোবা এবং সি ++ সিনট্যাক্স বা শব্দার্থবিজ্ঞান বোঝে না। ম্যাক্রোস নামস্থান, শ্রেণি বা ফাংশন ব্লকের মতো স্কোপগুলিকে উপেক্ষা করে, তাই আপনি উত্স ফাইলে অন্য কোনও কিছুর জন্য নাম ব্যবহার করতে পারবেন না। এটি যথাযথ সি ++ ভেরিয়েবল হিসাবে ধ্রুবক হিসাবে সংজ্ঞায়িত করা সত্য নয়:
#define MAX_HEIGHT 720
constexpr int max_height = 720;
class Window {
// ...
int max_height;
};
সদস্যের পরিবর্তনশীল বলা ভাল, max_heightকারণ এটি একটি শ্রেণীর সদস্য এবং তাই এর আলাদা সুযোগ রয়েছে, এবং নাম স্পেসের স্কোপ থেকে পৃথক। আপনি যদি সদস্যটির জন্য নামটি পুনঃব্যবহার করার চেষ্টা MAX_HEIGHTকরেন তবে প্রিপ্রসেসর এটিকে এই ননসেন্সে পরিবর্তন করে যা সংকলন করে না:
class Window {
// ...
int 720;
};
এ কারণেই আপনাকে ম্যাক্রোগুলি দিতে UGLY_SHOUTY_NAMESহবে যাতে তারা দাঁড়ায় এবং আপনি সংঘর্ষ এড়াতে তাদের নামকরণ সম্পর্কে যত্নবান হতে পারেন। যদি আপনি অযথা ম্যাক্রোগুলি ব্যবহার না করেন তবে আপনাকে সে সম্পর্কে চিন্তা করতে হবে না (এবং পড়তে হবে না SHOUTY_NAMES)।
আপনি যদি কোনও ফাংশনের ভিতরে কেবল ধ্রুবক চান তবে আপনি ম্যাক্রোর সাহায্যে এটি করতে পারবেন না, কারণ প্রিপ্রসেসর জানেন না যে কোনও ফাংশন কী বা এর অভ্যন্তরে কী বোঝায়। কোনও ম্যাক্রোকে কেবলমাত্র একটি ফাইলের নির্দিষ্ট অংশে সীমাবদ্ধ করতে আপনার #undefএটির আবার দরকার :
int limit(int height) {
#define MAX_HEIGHT 720
return std::max(height, MAX_HEIGHT);
#undef MAX_HEIGHT
}
অনেক বেশি বুদ্ধিমানের সাথে তুলনা করুন:
int limit(int height) {
constexpr int max_height = 720;
return std::max(height, max_height);
}
আপনি ম্যাক্রোটিকে কেন পছন্দ করবেন?
একটি কনসেক্সট্রপ ভেরিয়েবল একটি পরিবর্তনশীল তাই এটি প্রোগ্রামে আসলে বিদ্যমান থাকে এবং আপনি সাধারণ সি +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 0
এই কোডটির অপরিবর্তিত আচরণ রয়েছে:
#define MAX_HEIGHT 720
int limit(int height) {
const int& h = std::max(height, MAX_HEIGHT);
// ...
return h;
}
সমস্যাটি হ'ল এটি MAX_HEIGHTকোনও পরিবর্তনশীল নয়, সুতরাং std::maxএকটি অস্থায়ী কলটির জন্য intকম্পাইলার তৈরি করতে হবে। std::maxএরপরে ফিরে আসা রেফারেন্সটি সম্ভবত সেই অস্থায়ীটিকে বোঝায়, যা বিবৃতিটি শেষ হওয়ার পরে অস্তিত্বহীন, তাই return hঅবৈধ স্মৃতিতে অ্যাক্সেস করে।
এই সমস্যাটি কেবল সঠিক পরিবর্তনশীল সহ অস্তিত্বহীন, কারণ এটির স্মৃতিতে একটি নির্দিষ্ট অবস্থান রয়েছে যা চলে না:
int limit(int height) {
constexpr int max_height = 720;
const int& h = std::max(height, max_height);
// ...
return h;
}
(বাস্তবে আপনি সম্ভবত ঘোষণা int hনা করতেন const int& hতবে আরও সূক্ষ্ম প্রসঙ্গে সমস্যাটি দেখা দিতে পারে))
ম্যাক্রোকে পছন্দ করার একমাত্র সময় হ'ল যখন আপনার প্রিপ্রসেসর দ্বারা এটির মান বোঝার প্রয়োজন হয়, #ifশর্তে ব্যবহারের জন্য , যেমন
#define MAX_HEIGHT 720
#if MAX_HEIGHT < 256
using height_type = unsigned char;
#else
using height_type = unsigned int;
#endif
আপনি এখানে কোনও ভেরিয়েবল ব্যবহার করতে পারেননি, কারণ প্রিপ্রোসেসর বুঝতে পারে না কীভাবে নাম দ্বারা ভেরিয়েবলগুলি কীভাবে উল্লেখ করা যায়। এটি কেবল ম্যাক্রো সম্প্রসারণ এবং দিকনির্দেশক #(যেমন #includeএবং #defineএবং #if) এর মাধ্যমে প্রাথমিক খুব বেসিক জিনিসগুলি বোঝে ।
আপনি যদি এমন একটি ধ্রুবক চান যা প্রিপ্রোসেসর দ্বারা বোঝা যায় তবে আপনার এটি সংজ্ঞায়িত করার জন্য প্রিপ্রসেসর ব্যবহার করা উচিত। আপনি যদি সাধারণ সি ++ কোডের জন্য ধ্রুবক চান তবে সাধারণ সি ++ কোড ব্যবহার করুন।
উপরের উদাহরণটি কেবলমাত্র একটি প্রিপ্রোসেসর শর্ত প্রদর্শন করার জন্য, তবে এমনকি কোডটি প্রিপ্রসেসর ব্যবহার করে এড়াতে পারে:
using height_type = std::conditional_t<max_height < 256, unsigned char, unsigned int>;
constexprভেরিয়েবলের ঠিকানা (পয়েন্টার / রেফারেন্স) না নেওয়া পর্যন্ত স্মৃতি দখল করা উচিত নয়; অন্যথায়, এটি সম্পূর্ণরূপে অপ্টিমাইজ করা যেতে পারে (এবং আমি মনে করি যে স্ট্যান্ডার্ডিজ এটির নিশ্চয়তা দেয়)। আমি এটির উপরে জোর দিতে চাই যাতে লোকেরা enumভুল ধারণা থেকে পুরানো, নিকৃষ্ট ' হ্যাক' ব্যবহার অবিরত না করে যে কোনও তুচ্ছ ঘটনাকে constexprস্টোরেজের প্রয়োজন হয় না তবুও তারা কিছু দখল করবে।
int heightতবে ম্যাক্রোর মতোই আপনার সমস্যা হবে, কারণ এর ব্যাপ্তিটি মূলত অস্থায়ীভাবেও ফাংশনটির সাথে আবদ্ধ। ৩. উপরের মন্তব্যটি, "কনস্ট্যান্ট এবং এইচ অস্থায়ীর জীবনকাল বাড়িয়ে দেবে" সঠিক।
limit, সমস্যাটি হল ফেরতের মান std::max। ২. হ্যাঁ, সে কারণেই এটি কোনও রেফারেন্স দেয় না। ৩. ভুল, উপরে কলিরু লিঙ্কটি দেখুন।
const int& h = max(x, y);এবং maxমান অনুসারে তার ফেরতের মানটির আজীবন প্রসারিত হয়। রিটার্ন টাইপের দ্বারা নয়, তবে const int&এটি আবদ্ধ। আমি যা লিখেছি তা সঠিক।
সাধারণভাবে বলতে গেলে, আপনি constexprযখনই পারেন ব্যবহার করা উচিত , এবং অন্য কোনও সমাধান সম্ভব না হলে কেবল ম্যাক্রোগুলি ব্যবহার করা উচিত ।
ম্যাক্রোস কোডের একটি সহজ প্রতিস্থাপন এবং এই কারণে তারা প্রায়শই সংঘাত তৈরি করে (যেমন উইন্ডোজ। maxম্যাক্রো বনাম std::max)। অতিরিক্তভাবে, ম্যাক্রো যা কাজ করে তা সহজেই অন্যভাবে ব্যবহার করা যেতে পারে যা বিস্ময়কর সংকলনের ত্রুটিগুলি ট্রিগার করতে পারে। (যেমন Q_PROPERTYকাঠামোর সদস্যদের জন্য ব্যবহৃত)
এই সমস্ত অনিশ্চয়তার কারণে ম্যাক্রোগগুলি এড়ানো ভাল কোড স্টাইল, ঠিক যেমন আপনি সাধারণত গোটোস এড়িয়ে চলেন।
constexpr শব্দার্থগতভাবে সংজ্ঞায়িত করা হয় এবং এটি সাধারণত কম কম সমস্যা উত্পন্ন করে।
#ifঅর্থাত্ প্রিপ্রসেসর ব্যবহারকারী জিনিসগুলি ব্যবহার করে । ধ্রুবককে সংজ্ঞায়িত করা প্রিপ্রোসেসরগুলির পক্ষে অন্যতম কার্যকর নয়, যদি না ধ্রুবকটি অবশ্যই ম্যাক্রো হওয়া উচিত কারণ এটি প্রিপ্রসেসর ব্যবহারের ক্ষেত্রে ব্যবহার করা হয় #if। ধ্রুবকটি যদি সাধারণ সি ++ কোডে ব্যবহারের জন্য হয় (প্রিপ্রোসেসর নির্দেশিকা নয়) তবে একটি সাধারণ সি ++ ভেরিয়েবল ব্যবহার করুন, প্রিপ্রোসেসর ম্যাক্রো নয়।
জোনাথন ওয়েকেলি দ্বারা দুর্দান্ত উত্তর । আমি আপনাকে জোগোজাপানের জবাবটি একবার দেখে নিনconst এবং constexprআপনি ম্যাক্রোগুলির ব্যবহার বিবেচনা করার আগে তার মধ্যে পার্থক্য কী তা আগে একবার দেখে নিতে পরামর্শ দিয়েছি ।
ম্যাক্রোগুলি বোবা, তবে একটি ভাল উপায়ে। সম্ভবত আজকাল তারা আপনার বিল্ড-এইড হয়ে থাকে যখন আপনি চান আপনার কোডের খুব নির্দিষ্ট অংশগুলি কেবল নির্দিষ্ট সংজ্ঞাযুক্ত পরামিতিগুলির উপস্থিতিতে "সংজ্ঞায়িত" হয়ে সংকলিত করতে চান। সাধারণত, সব মানে এখনো ভাল আপনার ম্যাক্রো নাম, বা নিচ্ছে, এর একটি কল দিন Triggerএবং যোগ করার জিনিস, পছন্দ /D:Trigger, -DTriggerবিল্ড সরঞ্জাম, ইত্যাদি ব্যবহার করা হচ্ছে।
ম্যাক্রোগুলির বিভিন্ন রকম ব্যবহারের সময়, এই দুটি আমিই প্রায়শই দেখি যা খারাপ / পুরানো তারিখগুলি নয়:
সুতরাং আপনি যখন ওপি-র ক্ষেত্রে কোনও আন্ত constexprবা সংজ্ঞা নির্ধারণের একই লক্ষ্য অর্জন MACROকরতে পারেন, আধুনিক সম্মেলনগুলি ব্যবহার করার সময় দু'জনেরই ওভারল্যাপ হওয়ার সম্ভাবনা কম। এখানে কিছু সাধারণ ম্যাক্রো-ব্যবহার রয়েছে যা পর্যায়ক্রমে হয়নি, এখনও।
#if defined VERBOSE || defined DEBUG || defined MSG_ALL
// Verbose message-handling code here
#endif
ম্যাক্রো-ব্যবহারের জন্য অন্য উদাহরণ হিসাবে, আসুন আমরা বলি যে আপনার কাছে মুক্তি পাওয়ার জন্য কিছু আসন্ন হার্ডওয়্যার রয়েছে বা সম্ভবত এটির একটি নির্দিষ্ট প্রজন্মের কিছু জটিল কাজ রয়েছে যা অন্যদের প্রয়োজন হয় না। আমরা এই ম্যাক্রোটিকে হিসাবে সংজ্ঞায়িত করব GEN_3_HW।
#if defined GEN_3_HW && defined _WIN64
// Windows-only special handling for 64-bit upcoming hardware
#elif defined GEN_3_HW && defined __APPLE__
// Special handling for macs on the new hardware
#elif !defined _WIN32 && !defined __linux__ && !defined __APPLE__ && !defined __ANDROID__ && !defined __unix__ && !defined __arm__
// Greetings, Outlander! ;)
#else
// Generic handling
#endif