আমি আমার নির্মাতাদের সাথে সদস্য সূচনা তালিকা ব্যবহারের পক্ষে আংশিক ... তবে আমি দীর্ঘদিন থেকে এর পিছনে কারণগুলি ভুলে গিয়েছি ...
আপনি কি আপনার নির্মাতাদের সদস্য সূচনা তালিকা ব্যবহার করেন? যদি তাই হয় তবে কেন? তা না হলে কেন?
আমি আমার নির্মাতাদের সাথে সদস্য সূচনা তালিকা ব্যবহারের পক্ষে আংশিক ... তবে আমি দীর্ঘদিন থেকে এর পিছনে কারণগুলি ভুলে গিয়েছি ...
আপনি কি আপনার নির্মাতাদের সদস্য সূচনা তালিকা ব্যবহার করেন? যদি তাই হয় তবে কেন? তা না হলে কেন?
উত্তর:
জন্য POD বর্গ সদস্য, এতে কোন পার্থক্য নেই, এটা শৈলী শুধু একটি ব্যাপার। শ্রেণীর সদস্যদের জন্য যা ক্লাস হয়, তারপরে এটি কোনও ডিফল্ট কনস্ট্রাক্টরের একটি অপ্রয়োজনীয় কল এড়িয়ে যায়। বিবেচনা:
class A
{
public:
A() { x = 0; }
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B()
{
a.x = 3;
}
private:
A a;
};
এই ক্ষেত্রে, কনস্ট্রাক্টরর জন্য B
ডিফল্ট কনস্ট্রাক্টরকে কল করবে A
এবং তারপরে initial এ নামকরণ a.x
করবে A আরও ভাল উপায় এর প্রাথমিকভাবে তালিকার তালিকার কনস্ট্রাক্টরকে B
সরাসরি কল করার জন্য আরও ভাল উপায় হবে A
:
B()
: a(3)
{
}
এটি কেবলমাত্র A
এর A(int)
কনস্ট্রাক্টরকে কল করবে এটির ডিফল্ট কনস্ট্রাক্টর নয়। এই উদাহরণে, পার্থক্যটি নগন্য নয়, তবে কল্পনা করুন যে আপনি যদি A
ডিফল্ট নির্মাতারা আরও কিছু করেছিলেন যেমন মেমরি বরাদ্দ করা বা ফাইল খোলার মতো। আপনি অযথা এটি করতে চাইবেন না।
তদুপরি, যদি কোনও শ্রেণীর ডিফল্ট কনস্ট্রাক্টর না থাকে বা আপনার const
সদস্য ভেরিয়েবল থাকে তবে আপনাকে অবশ্যই একটি প্রাথমিক তালিকা ব্যবহার করতে হবে :
class A
{
public:
A(int x_) { x = x_; }
int x;
};
class B
{
public:
B() : a(3), y(2) // 'a' and 'y' MUST be initialized in an initializer list;
{ // it is an error not to do so
}
private:
A a;
const int y;
};
উপরে বর্ণিত পারফরম্যান্সের কারণগুলি ছাড়াও, যদি আপনার শ্রেণীর কনস্ট্রাক্টর প্যারামিটার হিসাবে পাস করা অবজেক্টের রেফারেন্স বা আপনার ক্লাসে কনস্ট ভেরিয়েবল থাকে তবে আপনার আরম্ভের তালিকা ব্যবহার করা ছাড়া কোনও বিকল্প নেই।
কনস্ট্রাক্টর ইনিশিয়ালাইজার তালিকা ব্যবহারের একটি গুরুত্বপূর্ণ কারণ যা এখানে উত্তরে উল্লেখ করা হয়নি তা হল বেস শ্রেণির সূচনা।
নির্মাণের আদেশ অনুযায়ী শিশু শ্রেণির আগে বেস ক্লাস তৈরি করা উচিত। কনস্ট্রাক্টর ইনিশিয়ালাইজার তালিকা ব্যতীত এটি সম্ভব যদি আপনার বেস ক্লাসে ডিফল্ট কনস্ট্রাক্টর থাকে যা শিশু শ্রেণির নির্মাতাকে প্রবেশের ঠিক আগে ডাকা হবে।
তবে, যদি আপনার বেস ক্লাসে কেবলমাত্র প্যারামিটারাইজড কনস্ট্রাক্টর থাকে তবে আপনার বেস ক্লাসটি শিশু শ্রেণির আগে আরম্ভ করা হয়েছে তা নিশ্চিত করতে আপনাকে অবশ্যই কনস্ট্রাক্টর ইনিশিয়ালাইজার তালিকাটি ব্যবহার করতে হবে।
সাবোবজেক্টগুলির সূচনা যা কেবলমাত্র প্যারামিটারাইজড কনস্ট্রাক্টর রয়েছে
দক্ষতা
কনস্ট্রাক্টর ইনিশিয়ালাইজার তালিকাটি ব্যবহার করে আপনি আপনার ডেটা সদস্যদের প্রথমে তাদের ডিফল্ট অবস্থায় আরম্ভ করার পরিবর্তে আপনার কোডে যা প্রয়োজন তার সঠিক অবস্থানে আরম্ভ করুন এবং তারপরে আপনার কোডে আপনার প্রয়োজন অনুযায়ী তাদের রাষ্ট্র পরিবর্তন করুন।
যদি আপনার শ্রেণিতে স্থিতিহীন কনস্টের ডেটা সদস্যদের ডিফল্ট কনস্ট্রাক্টর থাকে এবং আপনি কন্সট্রাক্টর ইনিশিয়ালাইজার তালিকাটি ব্যবহার না করেন তবে আপনি তাদের পূর্বনির্ধারিত অবস্থায় আরম্ভ করা হবে বলে আপনি তাদের উদ্দেশ্যপ্রাপ্ত অবস্থায় আরম্ভ করতে পারবেন না।
সংকলক নির্মাণকারীর প্রবেশের সময় রেফারেন্স ডেটা সদস্যদের অবশ্যই নিখুঁত হতে হবে কারণ পরে কেবলমাত্র উল্লেখ করা যায় না এবং পরে আরম্ভ করা যায় না। এটি কেবল কনস্ট্রাক্টর আরম্ভকারী তালিকা দিয়েই সম্ভব with
পারফরম্যান্স ইস্যুগুলির পরে, আরও একটি গুরুত্বপূর্ণ বিষয় রয়েছে যা আমি কোড রক্ষণাবেক্ষণ এবং প্রসারযোগ্যতা কল করব।
যদি কোনও টি পিওড হয় এবং আপনি আরম্ভের তালিকাকে অগ্রাধিকার দেওয়া শুরু করেন, তবে যদি এক সময় টি নন-পড টাইপ-এ পরিবর্তিত হয় তবে অপ্রয়োজনীয় কন্সট্রাক্টর কলগুলি এড়াতে আপনার আরম্ভের চারপাশে কোনও পরিবর্তন করার দরকার নেই কারণ এটি ইতিমধ্যে অনুকূলিত।
টাইপ টিতে যদি ডিফল্ট কনস্ট্রাক্টর এবং এক বা একাধিক ব্যবহারকারী-সংজ্ঞায়িত কনস্ট্রাক্টর থাকে এবং আপনি একবারে ডিফল্টটিকে অপসারণ বা আড়াল করার সিদ্ধান্ত নেন, তবে আরম্ভের তালিকাটি যদি ব্যবহার করা হয় তবে আপনার ব্যবহারকারী-সংজ্ঞায়িত কনস্ট্রাক্টরগুলি আপনাকে কোড আপডেট করার দরকার নেই কারণ তারা ইতিমধ্যে সঠিকভাবে প্রয়োগ করা হয়েছে।
কনস্টের সদস্য বা রেফারেন্স সদস্যদের সাথে একইভাবে, আসুন শুরুতে টি নীচের হিসাবে সংজ্ঞায়িত করা হয়:
struct T
{
T() { a = 5; }
private:
int a;
};
এরপরে, আপনি কনস্ট হিসাবে যোগ্যতার সিদ্ধান্ত নেবেন, যদি আপনি প্রথম থেকেই সূচনা তালিকাটি ব্যবহার করেন তবে এটি একটি একক লাইন পরিবর্তন ছিল, তবে উপরে বর্ণিত টি সংজ্ঞায়িত করার সাথে সাথে অ্যাসাইনমেন্টটি সরাতে কনস্ট্রাক্টরের সংজ্ঞাও খনন করতে হবে:
struct T
{
T() : a(5) {} // 2. that requires changes here too
private:
const int a; // 1. one line change
};
এটি কোনও গোপন বিষয় নয় যে রক্ষণাবেক্ষণ করা খুব সহজ এবং ত্রুটি-ঝুঁকির চেয়ে কম যদি কোড কোনও "কোড বানর" না লিখেছিলেন তবে একজন ইঞ্জিনিয়ার যিনি কী করছেন সে সম্পর্কে গভীর বিবেচনার ভিত্তিতে সিদ্ধান্ত নেয়।
কনস্ট্রাক্টরের বডি চালানোর আগে, সমস্ত তার কনস্ট্রাক্টরগুলি এর প্যারেন্ট ক্লাস এবং তার ক্ষেত্রগুলির জন্য ডাকা হয়। ডিফল্টরূপে, নো-আর্গুমেন্ট কনস্ট্রাক্টরগণকে অনুরোধ করা হয়। আরম্ভের তালিকাগুলি আপনাকে কোন কনস্ট্রাক্টর বলা হয় এবং কনস্ট্রাক্টর কী আর্গুমেন্ট গ্রহণ করে তা চয়ন করতে দেয়।
আপনার যদি রেফারেন্স বা কনস্ট ক্ষেত্র থাকে, বা ব্যবহৃত ক্লাসগুলির মধ্যে একটিতে যদি ডিফল্ট কনস্ট্রাক্টর না থাকে তবে আপনাকে অবশ্যই একটি সূচনা তালিকা ব্যবহার করতে হবে।
// Without Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
variable = a;
}
};
এখানে সংকলক MyClass
1 টাইপ করে একটি অবজেক্ট তৈরি করতে নিম্নলিখিত পদক্ষেপগুলি অনুসরণ করে Type টাইপ এর কনস্ট্রাক্টরকে প্রথমে "এ" এর জন্য ডাকা হয়।
২. "টাইপ" এর অ্যাসাইনমেন্ট অপারেটরকে নির্ধারিত করতে MyClass () কনস্ট্রাক্টরের বডির ভিতরে ডাকা হয়
variable = a;
এবং অবশেষে "টাইপ" এর ডেস্ট্রাক্টরকে "এ" বলা হয় কারণ এটি সুযোগের বাইরে চলে যায়।
এখন মাইক্লাস () নির্ধারকের সাথে ইনিশিয়ালার তালিকার সাথে একই কোডটি বিবেচনা করুন
// With Initializer List
class MyClass {
Type variable;
public:
MyClass(Type a):variable(a) { // Assume that Type is an already
// declared class and it has appropriate
// constructors and operators
}
};
ইনিশিয়ালাইজার তালিকার সাহায্যে নিম্নলিখিত পদক্ষেপগুলি সংকলক অনুসরণ করে:
সদস্য আরম্ভের তালিকাটি কতটা পার্থক্য তৈরি করতে পারে তা প্রদর্শনের জন্য কেবল কিছু অতিরিক্ত তথ্য যুক্ত করা । লেটকোড 303 রেঞ্জের যোগফলে - অপরিবর্তনীয়, https://leetcode.com/problems/range-sum-query-immutable/ , যেখানে আপনাকে নির্দিষ্ট আকারের সাথে একটি ভেক্টর শূন্য করতে আরম্ভ করতে হবে। এখানে দুটি পৃথক বাস্তবায়ন এবং গতির তুলনা করা হচ্ছে।
সদস্য সূচনা তালিকা ছাড়া এসি পেতে আমার প্রায় 212 এমএস ব্যয় করতে হয় ।
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) {
preSum = vector<int>(nums.size()+1, 0);
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
এখন সদস্য আরম্ভের তালিকাটি ব্যবহার করে এসি পাওয়ার সময়টি প্রায় 108 এমএস । এই সাধারণ উদাহরণ সহ, এটি একেবারে স্পষ্ট যে, সদস্য সূচনা তালিকাটি আরও কার্যকর । সমস্ত পরিমাপ এলসি থেকে চলমান সময় থেকে।
class NumArray {
public:
vector<int> preSum;
NumArray(vector<int> nums) : preSum(nums.size()+1, 0) {
int ps = 0;
for (int i = 0; i < nums.size(); i++)
{
ps += nums[i];
preSum[i+1] = ps;
}
}
int sumRange(int i, int j) {
return preSum[j+1] - preSum[i];
}
};
বাক্য গঠন:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample(): Sam_x(1), Sam_y(2) /* Classname: Initialization List */
{
// Constructor body
}
};
প্রারম্ভিক তালিকার প্রয়োজন:
class Sample
{
public:
int Sam_x;
int Sam_y;
Sample() */* Object and variables are created - i.e.:declaration of variables */*
{ // Constructor body starts
Sam_x = 1; */* Defining a value to the variable */*
Sam_y = 2;
} // Constructor body ends
};
উপরের প্রোগ্রামে, যখন ক্লাসের কনস্ট্রাক্টর এক্সিকিউট হয় স্যাম_এক্স এবং স্যাম_ই তৈরি হয়। তারপরে কনস্ট্রাক্টর বডিতে, সেই সদস্যদের ডেটা ভেরিয়েবল সংজ্ঞায়িত করা হয়।
ব্যবহারের ক্ষেত্রে:
সিতে, ভেরিয়েবলগুলি তৈরি করার সময় সংজ্ঞায়িত করতে হবে। সি ++ তে একইভাবে, আমাদের সূচনা তালিকা ব্যবহার করে অবজেক্ট তৈরির সময় কনস্ট এবং রেফারেন্স ভেরিয়েবলটি শুরু করতে হবে। যদি আমরা অবজেক্ট তৈরির (ইনসাইডার কনস্ট্রাক্টর বডি) পরে ইনিশিয়েলেশন করি তবে আমরা সংকলনের সময় ত্রুটি পেয়ে যাব।
স্যাম্পল 1 (বেস) শ্রেণীর সদস্য অবজেক্টস যাদের ডিফল্ট কনস্ট্রাক্টর নেই
class Sample1
{
int i;
public:
Sample1 (int temp)
{
i = temp;
}
};
// Class Sample2 contains object of Sample1
class Sample2
{
Sample1 a;
public:
Sample2 (int x): a(x) /* Initializer list must be used */
{
}
};
ডেরিভেড ক্লাসের জন্য অবজেক্ট তৈরি করার সময় যা অভ্যন্তরীণভাবে ডেরিভড ক্লাস কনস্ট্রাক্টরকে কল করবে এবং বেস ক্লাস কনস্ট্রাক্টরকে কল করবে (ডিফল্ট)। যদি বেস ক্লাসে ডিফল্ট কনস্ট্রাক্টর না থাকে তবে ব্যবহারকারী সংকলন সময় ত্রুটি পাবে। এড়াতে আমাদের অবশ্যই থাকা উচিত
1. Default constructor of Sample1 class
2. Initialization list in Sample2 class which will call the parametric constructor of Sample1 class (as per above program)
ক্লাস কনস্ট্রাক্টরের প্যারামিটারের নাম এবং একটি ক্লাসের ডেটা সদস্য একই:
class Sample3 {
int i; /* Member variable name : i */
public:
Sample3 (int i) /* Local variable name : i */
{
i = i;
print(i); /* Local variable: Prints the correct value which we passed in constructor */
}
int getI() const
{
print(i); /*global variable: Garbage value is assigned to i. the expected value should be which we passed in constructor*/
return i;
}
};
যেমনটি আমরা সবাই জানি, স্থানীয় ভেরিয়েবলের সর্বোচ্চ অগ্রাধিকার থাকলে বৈশ্বিক চলক যদি উভয় ভেরিয়েবলের একই নাম থাকে। এই ক্ষেত্রে, প্রোগ্রামটি "i" মান consider উভয় বাম এবং ডান পাশের ভেরিয়েবল বিবেচনা করে। যেমন: i = i S স্থানীয় নমুনা হিসাবে নমুনা 3 () কনস্ট্রাক্টর এবং ক্লাস সদস্য ভেরিয়েবল (i) ওভাররাইড পেয়েছে। এড়াতে, আমাদের অবশ্যই ব্যবহার করা উচিত
1. Initialization list
2. this operator.
C ++ কোর গাইডলাইনস C.49- তে ব্যাখ্যা করা হয়েছে : কনস্ট্রাক্টরগুলিতে অ্যাসাইনমেন্টের জন্য প্রাথমিককরণ পছন্দ করুন এটি ডিফল্ট কনস্ট্রাক্টরগুলিতে অপ্রয়োজনীয় কলগুলি বাধা দেয়।