আমি কখনই কেন এমন করব তা আমি বুঝতে পারি না:
struct S {
int a;
S(int aa) : a(aa) {}
S() = default;
};
কেন শুধু বলবেন না:
S() {} // instead of S() = default;
কেন এটির জন্য একটি নতুন সিনট্যাক্স আনা?
আমি কখনই কেন এমন করব তা আমি বুঝতে পারি না:
struct S {
int a;
S(int aa) : a(aa) {}
S() = default;
};
কেন শুধু বলবেন না:
S() {} // instead of S() = default;
কেন এটির জন্য একটি নতুন সিনট্যাক্স আনা?
উত্তর:
একটি ডিফল্ট ডিফল্ট কনস্ট্রাক্টর বিশেষত কোনও ব্যবহারকারী-সংজ্ঞায়িত ডিফল্ট কনস্ট্রাক্টর হিসাবে একই হিসাবে কোনও আরম্ভের তালিকা এবং খালি যৌগিক বিবৃতি না হিসাবে সংজ্ঞায়িত হয়।
§12.1 / 6 [class.ctor] একটি ডিফল্ট কনস্ট্রাক্টর যা ডিফল্ট হয় এবং মুছে ফেলা হিসাবে সংজ্ঞায়িত হয় না তা স্পষ্টভাবে সংজ্ঞায়িত হয় যখন এটি তার শ্রেণীর ধরণের একটি অবজেক্ট তৈরি করতে অদ্ভুতভাবে ব্যবহৃত হয় বা যখন এটি প্রথম ঘোষণার পরে স্পষ্টতই খেলাপি হয়। সুস্পষ্টভাবে সংজ্ঞায়িত ডিফল্ট কনস্ট্রাক্টর ক্লাসের প্রারম্ভিককরণের সেটটি সম্পাদন করে যা কোনও শ্রেণীর জন্য কোনও ব্যবহারকারী-লিখিত ডিফল্ট কনস্ট্রাক্টর দ্বারা সঞ্চালিত হবে যার কোনও সিটার-ইনিশিয়ালাইজার (12.6.2) এবং একটি খালি যৌগিক বিবৃতি নেই। [...]
যাইহোক, উভয় নির্মাণকারী একই আচরণ করবে, খালি বাস্তবায়ন সরবরাহ করা শ্রেণীর কিছু বৈশিষ্ট্যকে প্রভাবিত করে। ব্যবহারকারী-নির্ধারিত কন্সট্রাকটর টাইপ একটি না দেওয়ার, যদিও এটা কিছুই না, করে তোলে সমষ্টিগত এবং না তুচ্ছ । আপনি যদি চান যে আপনার শ্রেণি একটি সমষ্টি বা তুচ্ছ ধরনের হতে পারে (বা ট্রানজিটিভিটি দ্বারা, একটি পিওডি টাইপ), তবে আপনাকে ব্যবহার করা দরকার = default
।
§8.5.1 / 1 [dcl.init.aggr] একটি সমষ্টি হ'ল একটি অ্যারে বা শ্রেণি যা ব্যবহারকারীর দ্বারা সরবরাহ করা কোনও কনস্ট্রাক্টর নেই, [এবং ...]
§12.1 / 5 [class.ctor] একটি ডিফল্ট কনস্ট্রাক্টর যদি এটি ব্যবহারকারী-সরবরাহ না করে এবং [...]
§9 / 6 [বর্গ] একটি তুচ্ছ শ্রেণি একটি শ্রেণি যা একটি তুচ্ছ ডিফল্ট নির্মাণকারী এবং [...]
প্রদর্শন করার জন্যে:
#include <type_traits>
struct X {
X() = default;
};
struct Y {
Y() { };
};
int main() {
static_assert(std::is_trivial<X>::value, "X should be trivial");
static_assert(std::is_pod<X>::value, "X should be POD");
static_assert(!std::is_trivial<Y>::value, "Y should not be trivial");
static_assert(!std::is_pod<Y>::value, "Y should not be POD");
}
অতিরিক্তভাবে, স্পষ্টত কোনও কনস্ট্রাক্টরকে ডিফল্ট করা এটিকে তৈরি করবে constexpr
যদি অন্তর্নিহিত কনস্ট্রাক্টর থাকত এবং এটিকে একই ব্যতিক্রম স্পেসিফিকেশনটি দেবে যা অন্তর্নিহিত কনস্ট্রাক্টরের কাছে থাকত। আপনার দেওয়া ক্ষেত্রে, অন্তর্নিহিত কনস্ট্রাক্টরটি না হত constexpr
(কারণ এটি কোনও ডেটা সদস্যকে অবিচ্ছিন্ন করে ফেলেছিল) এবং এতে খালি ব্যতিক্রমের স্পেসিফিকেশনও থাকবে, সুতরাং কোনও পার্থক্য নেই। তবে হ্যাঁ, সাধারণ ক্ষেত্রে আপনি ম্যানুয়ালি নির্দিষ্ট করতে পারেন constexpr
এবং অন্তর্ভুক্ত নির্মাতার সাথে মেলে ব্যতিক্রমের বিশদটি।
ব্যবহার করা = default
কিছু অভিন্নতা এনে দেয়, কারণ এটি অনুলিপি / মুভ কনস্ট্রাক্টর এবং ডেস্ট্রাক্টরগুলির সাথেও ব্যবহার করা যেতে পারে। একটি খালি অনুলিপি নির্মাণকারী, উদাহরণস্বরূপ, খেলাপি কপি নির্মাণকারী হিসাবে একই কাজ করবে না (যা সদস্যদের সদস্য-ভিত্তিক অনুলিপি সম্পাদন করবে)। এই বিশেষ সদস্য ফাংশনের প্রত্যেকটির জন্য অভিন্নভাবে = default
(বা = delete
) বাক্য গঠন ব্যবহার করা আপনার কোডটি আপনার উদ্দেশ্যকে স্পষ্ট করে উল্লেখ করে পড়া সহজ করে তোলে।
constexpr
(7.1.5) পূরণ করতে পারে তবে স্পষ্টভাবে সংজ্ঞায়িত ডিফল্ট কনস্ট্রাক্টর হয় constexpr
" "
constexpr
, (খ) এটি স্পষ্টতই একই হিসাবে বিবেচিত হবে ব্যতিক্রম-স্পেসিফিকেশন যেমন এটি স্পষ্টভাবে ঘোষণা করা হয়েছিল (15.4), ... "এটি এই নির্দিষ্ট ক্ষেত্রে কোনও পার্থক্য রাখে না, তবে সাধারণভাবে foo() = default;
কিছুটা সুবিধা রয়েছে foo() {}
।
constexpr
(যেহেতু কোনও ডেটা সদস্য অবিচ্ছিন্নভাবে ছেড়ে যায়) এবং এর ব্যতিক্রমের বিবরণী সমস্ত ব্যতিক্রমকে মঞ্জুরি দেয়। আমি যে আরও পরিষ্কার করব।
constexpr
(যা আপনি উল্লেখ করেছেন এখানে কোনও পার্থক্য করা উচিত নয়): struct S1 { int m; S1() {} S1(int m) : m(m) {} }; struct S2 { int m; S2() = default; S2(int m) : m(m) {} }; constexpr S1 s1 {}; constexpr S2 s2 {};
কেবল s1
একটি ত্রুটি দেয়, না s2
। ঝনঝন এবং জি ++ উভয় ক্ষেত্রে।
আমার একটি উদাহরণ রয়েছে যা পার্থক্যটি দেখিয়ে দেবে:
#include <iostream>
using namespace std;
class A
{
public:
int x;
A(){}
};
class B
{
public:
int x;
B()=default;
};
int main()
{
int x = 5;
new(&x)A(); // Call for empty constructor, which does nothing
cout << x << endl;
new(&x)B; // Call for default constructor
cout << x << endl;
new(&x)B(); // Call for default constructor + Value initialization
cout << x << endl;
return 0;
}
আউটপুট:
5
5
0
যেমন আমরা দেখতে পাচ্ছি খালি এ () কনস্ট্রাক্টরের কল সদস্যদের আরম্ভ করে না, যখন বি () তা করে।
n2210 কিছু কারণ সরবরাহ করে:
খেলাপিদের পরিচালনাতে বেশ কয়েকটি সমস্যা রয়েছে:
- কনস্ট্রাক্টরের সংজ্ঞাগুলি মিলিত হয়; যেকোন কনস্ট্রাক্টরের ঘোষণা ডিফল্ট কনস্ট্রাক্টরকে দমন করে।
- ডেস্ট্রাক্টর ডিফল্ট পলিমারফিক ক্লাসে অনুপযুক্ত, এর একটি স্পষ্ট সংজ্ঞা প্রয়োজন।
- কোনও ডিফল্ট একবার চাপা পড়ে গেলে, এটি পুনরুত্থানের কোনও উপায় থাকে না।
- ডিফল্ট বাস্তবায়নগুলি ম্যানুয়ালি নির্দিষ্ট করা বাস্তবায়নগুলির চেয়ে প্রায়শই কার্যকর।
- অ-ডিফল্ট বাস্তবায়নগুলি অ-তুচ্ছ, যা শব্দার্থক প্রকারকে প্রভাবিত করে, যেমন একটি প্রকার নন-পিওডি করে।
- (অ-তুচ্ছ) বিকল্প ঘোষণা না করে কোনও বিশেষ সদস্য ফাংশন বা গ্লোবাল অপারেটর নিষিদ্ধ করার কোনও উপায় নেই।
type::type() = default; type::type() { x = 3; }
কিছু ক্ষেত্রে সদস্যদের ফাংশন সংজ্ঞা পরিবর্তন করার প্রয়োজন ছাড়াই শ্রেণীর সংস্থা পরিবর্তন করতে পারে কারণ অতিরিক্ত সদস্যদের ঘোষণার সাথে ডিফল্ট পরিবর্তন হয়।
তিনটি নিয়ম সি -+ 11 এর সাথে পাঁচটি-রুল-অফ হয়ে যায় দেখুন ? :
নোট করুন যে মুভ কনস্ট্রাক্টর এবং মুভ অ্যাসাইনমেন্ট অপারেটর এমন কোনও শ্রেণীর জন্য উত্পন্ন হবে না যা স্পষ্টভাবে অন্যান্য বিশেষ সদস্য ফাংশনগুলির কোনওরূপে ঘোষণা করে, কপি কনস্ট্রাক্টর এবং অনুলিপি অ্যাসাইনমেন্ট অপারেটর কোনও শ্রেণীর জন্য উত্পন্ন হবে না যা স্পষ্টভাবে একটি মুভ কনস্ট্রাক্টর বা সরানো ঘোষণা করে অ্যাসাইনমেন্ট অপারেটর এবং এটি স্পষ্টভাবে ঘোষিত ডেস্ট্রাক্টর এবং স্পষ্টভাবে সংজ্ঞায়িত অনুলিপি করা কপি নির্মাণকারী বা স্পষ্টরূপে সংজ্ঞায়িত অনুলিপি অপারেটর অপারেটর সহ একটি শ্রেণিকে অবহেলিত বলে বিবেচিত হয়
= default
করছেন কারণ সাধারণভাবে বদলে = default
করছেন বনাম একটি কন্সট্রাকটর উপর { }
।
{}
ইতিমধ্যে প্রবর্তনের পূর্বে ভাষার একটি বৈশিষ্ট্য ছিল =default
, এসব কারণেই কি পার্থক্য উপর নির্ভর পরোক্ষভাবে (যেমন বোঝা যে, "সেখানে পুনরুজ্জীবিত [একটি চাপা ডিফল্ট] এ কোন মানে হয়" {}
হয় না ডিফল্ট সমতূল্য )।
এটি কিছু ক্ষেত্রে শব্দার্থবিজ্ঞানের বিষয়। এটি ডিফল্ট নির্মাণকারীদের সাথে খুব সুস্পষ্ট নয়, তবে এটি অন্যান্য সংকলক উত্পাদিত সদস্য ফাংশনগুলির সাথে সুস্পষ্ট হয়ে যায়।
ডিফল্ট কনস্ট্রাক্টরের জন্য, কোনও শূন্য শরীরের সাথে কোনও ডিফল্ট কনস্ট্রাক্টরকে তুচ্ছ ব্যবহারকারীর জন্য প্রার্থী হিসাবে বিবেচনা করা সম্ভব হত =default
। সর্বোপরি, পুরানো খালি ডিফল্ট নির্মাতারা আইনী সি ++ ছিলেন ।
struct S {
int a;
S() {} // legal C++
};
সংকলক এই নির্মাতাটিকে তুচ্ছ বলে বোঝে বা না বোঝায় অপ্টিমাইজেশনের বাইরে (ম্যানুয়াল বা সংকলক) এর বেশিরভাগ ক্ষেত্রে অপ্রাসঙ্গিক।
তবে খালি ফাংশন বডিগুলিকে "ডিফল্ট" হিসাবে গণ্য করার এই প্রচেষ্টাটি অন্যান্য ধরণের সদস্য ফাংশনের জন্য পুরোপুরি বিচ্ছিন্ন হয়ে যায়। অনুলিপি নির্মাতা বিবেচনা করুন:
struct S {
int a;
S() {}
S(const S&) {} // legal, but semantically wrong
};
উপরের ক্ষেত্রে, খালি শরীরের সাথে লিখিত অনুলিপিটি এখন ভুল । এটি আসলে আর কিছুই অনুলিপি করে না। এটি ডিফল্ট অনুলিপি কন্সট্রাক্টর শব্দার্থকগুলির তুলনায় শব্দার্থবিদ্যার একটি খুব আলাদা সেট। কাঙ্ক্ষিত আচরণের জন্য আপনাকে কিছু কোড লিখতে হবে:
struct S {
int a;
S() {}
S(const S& src) : a(src.a) {} // fixed
};
এমনকি এই সহজ ক্ষেত্রে অবশ্য এটা অনেক বোঝা আরো কম্পাইলার তা যাচাই করতে কপি কন্সট্রাকটর এক এটি নিজেই উৎপন্ন হবে অভিন্ন জন্য হয়ে উঠছে যাওয়া বা এটি দেখতে যে কপি কন্সট্রাকটর হয় তুচ্ছ একটি করার জন্য (সমতুল্য memcpy
, মূলত )। সংকলকটি প্রতিটি সদস্য ইনিশিয়ালাইজার এক্সপ্রেশন পরীক্ষা করে দেখতে হবে এবং উত্সের সংশ্লিষ্ট সদস্যের অ্যাক্সেসের জন্য এটি অভিব্যক্তির অনুরূপ এবং অন্য কোনও কিছুই নিশ্চিত করতে হবে না, নিশ্চিত করে নিন যে কোনও সদস্যই তুচ্ছ তাত্ক্ষণিক ডিফল্ট নির্মাণ ইত্যাদির সাথে বাকী নয়। ইত্যাদি প্রক্রিয়াটির দিক থেকে এটি পিছনের দিকে রয়েছে সংকলকটি এই ফাংশনের নিজস্ব উত্পন্ন সংস্করণগুলি তুচ্ছ তা যাচাই করতে ব্যবহার করবে।
তারপরে কপির অ্যাসাইনমেন্ট অপারেটরটি বিবেচনা করুন যা এমনকি কেশিক পেতে পারে, বিশেষত অ-তুচ্ছ মামলায়। এটি এক টন বয়লার-প্লেট যা আপনাকে অনেক ক্লাসের জন্য লিখতে চায় না তবে আপনাকে যেভাবেই সি ++ 03 তে বাধ্য করা হবে:
struct T {
std::shared_ptr<int> b;
T(); // the usual definitions
T(const T&);
T& operator=(const T& src) {
if (this != &src) // not actually needed for this simple example
b = src.b; // non-trivial operation
return *this;
};
এটি একটি সহজ কেস, তবে এটি ইতিমধ্যে আরও বেশি কোড হিসাবে আপনি কখনও এ জাতীয় সরল প্রকারের জন্য লিখতে বাধ্য হতে চান T
(বিশেষত আমরা মিশ্রণে মুভি অপারেশন টস করে নিই)। আমরা "ডিফল্টগুলি পূরণ কর" যার অর্থ খালি শরীরের উপর নির্ভর করতে পারি না কারণ খালি শরীরটি ইতিমধ্যে পুরোপুরি বৈধ এবং এর স্পষ্ট অর্থ রয়েছে। প্রকৃতপক্ষে, যদি শূন্য শরীরটি "ডিফল্টগুলি পূরণ করুন" বোঝাতে ব্যবহৃত হয় তবে স্পষ্টভাবে কোনও অনি-অনুলিপি অনুলিপি নির্মাণকারী বা এটির মতো উপায় তৈরি করার উপায় নেই।
এটি আবার ধারাবাহিকতার বিষয়। খালি দেহটির অর্থ "কিছুই করা নয়" তবে অনুলিপি তৈরির মতো জিনিসের জন্য যা আপনি সত্যই "কিছু না" চান না বরং "দমন না করা অবস্থায় আপনি সাধারণত যা করেন তা করেন"। অত: পর =default
। কপি / মুভ কনস্ট্রাক্টর এবং অ্যাসাইনমেন্ট অপারেটরগুলির মতো দমন করা সংকলক উত্পাদিত সদস্য ফাংশনগুলি কাটিয়ে উঠার জন্য এটি প্রয়োজনীয় । এটি তখন ডিফল্ট কনস্ট্রাক্টরের জন্য কাজ করার জন্য এটি কেবল "সুস্পষ্ট"।
খালি দেহ এবং তুচ্ছ সদস্য / বেস কন্সট্রাক্টরগুলির সাথে ডিফল্ট কনস্ট্রাক্টর তৈরি করা ভাল হতে পারে তবে তারা =default
কিছুটা ক্ষেত্রে পুরানো কোডকে আরও অনুকূল করে তোলাও হত তবে বেশিরভাগ নিম্ন-স্তরের কোড তুচ্ছ উপর নির্ভর করে অপ্টিমাইজেশনের জন্য ডিফল্ট কনস্ট্রাক্টরগুলিও তুচ্ছ কপি নির্মাণকারীদের উপর নির্ভর করে। আপনি যদি আপনার সমস্ত পুরানো অনুলিপি নির্মাণকারীর যেতে এবং "ফিক্স" করতে চলেছেন তবে আপনার সমস্ত পুরানো ডিফল্ট কনস্ট্রাক্টরকে ঠিক করার জন্য এটি খুব বেশি পরিমাণে নয় either =default
আপনার উদ্দেশ্যগুলি বোঝাতে এটি স্পষ্টভাবে ব্যবহার করা আরও স্পষ্ট এবং আরও সুস্পষ্ট ।
আরও কয়েকটি জিনিস রয়েছে যা সংকলক-উত্পাদিত সদস্য ফাংশনগুলি করবে যা আপনাকে স্পষ্টভাবে সমর্থনে পরিবর্তন করতে হবে, পাশাপাশি। constexpr
ডিফল্ট নির্মাতাদের জন্য সমর্থন একটি উদাহরণ। =default
অন্যান্য সমস্ত বিশেষ কীওয়ার্ড এবং যেমন দ্বারা =default
বর্ণিত এবং যেটি সি ++ 11 এর থিমগুলির মধ্যে একটি ছিল: ভাষাটি সহজ করে তোলা হয়েছে তার মধ্যে ফাংশনগুলি চিহ্নিত করার চেয়ে মানসিকভাবে ব্যবহার করা সহজ। এটি এখনও প্রচুর পরিমাণে ওয়ার্টস এবং ব্যাক-কম্প্যাট সমঝোতা পেয়েছে তবে এটি স্পষ্ট যে ব্যবহারের সুবিধার্থে আসার পরে এটি C ++ 03 থেকে অনেক বড় পদক্ষেপ।
= default
করতে হবে a=0;
এবং ছিল না! আমি এটি পক্ষে ছিল : a(0)
। আমি এখনও বিভ্রান্ত হয়ে পড়েছি যে কতটা কার্যকর = default
, এটি কি পারফরম্যান্স সম্পর্কে? আমি শুধু ব্যবহার না হলে এটি কোথাও ভেঙে যাবে = default
? আমি এখানে সমস্ত উত্তর পড়ার চেষ্টা করেছিলাম কিনে আমি কিছু সি ++ স্টাফে নতুন এবং এটি বুঝতে আমার খুব সমস্যা হচ্ছে।
a=0
উদাহরণটি তুচ্ছ ধরণের আচরণের কারণে, যা একটি পৃথক (যদিও সম্পর্কিত) বিষয়।
= default
এবং এখনও অনুদান a
হবে =0
? কোনভাবে? আপনি কি মনে করেন যে আমি কীভাবে একটি নতুন প্রশ্ন তৈরি করতে পারি "কীভাবে একজন কনস্ট্রাক্টর রাখবেন = default
এবং ক্ষেত্রগুলি সঠিকভাবে শুরু করা হবে?", বিটিডব্লুতে আমার সমস্যা ছিল একটি struct
এবং একটিতে নয় class
, এবং অ্যাপটি সঠিকভাবে চলছে না এমনকি ব্যবহার হচ্ছে না = default
, আমি করতে পারি যদি এটি ভাল হয় তবে এই প্রশ্নের একটি ন্যূনতম কাঠামো যুক্ত করুন :)
struct { int a = 0; };
আপনি যদি সিদ্ধান্ত নেন তবে আপনার কোনও কনস্ট্রাক্টর দরকার, আপনি এটি ডিফল্ট করতে পারেন তবে নোট করুন যে প্রকারটি তুচ্ছ হবে না (যা ভাল)।
এর অবচয় std::is_pod
এবং তার বিকল্পের কারণে std::is_trivial && std::is_standard_layout
, @ জোসেফম্যানসফিল্ডের উত্তর থেকে স্নিপেটটি হয়ে যায়:
#include <type_traits>
struct X {
X() = default;
};
struct Y {
Y() {}
};
int main() {
static_assert(std::is_trivial_v<X>, "X should be trivial");
static_assert(std::is_standard_layout_v<X>, "X should be standard layout");
static_assert(!std::is_trivial_v<Y>, "Y should not be trivial");
static_assert(std::is_standard_layout_v<Y>, "Y should be standard layout");
}
মনে রাখবেন যে এটি Y
এখনও স্ট্যান্ডার্ড লেআউটের।
default
কোনও নতুন কীওয়ার্ড নয়, এটি ইতিমধ্যে সংরক্ষিত কীওয়ার্ডের নতুন ব্যবহার।