বন্ধনী-সংযুক্ত আরম্ভকারী কখন ব্যবহার করবেন?


97

সি ++ ১১-এ, ক্লাস শুরুর জন্য আমাদের কাছে সেই নতুন বাক্য গঠন রয়েছে যা ভেরিয়েবলকে কীভাবে আরম্ভ করার জন্য আমাদের একটি বিশাল সংখ্যক সম্ভাবনা দেয়।

{ // Example 1
  int b(1);
  int a{1};
  int c = 1;
  int d = {1};
}
{ // Example 2
  std::complex<double> b(3,4);
  std::complex<double> a{3,4};
  std::complex<double> c = {3,4};
  auto d = std::complex<double>(3,4);
  auto e = std::complex<double>{3,4};
}
{ // Example 3
  std::string a(3,'x');
  std::string b{3,'x'}; // oops
}
{ // Example 4
  std::function<int(int,int)> a(std::plus<int>());
  std::function<int(int,int)> b{std::plus<int>()};
}
{ // Example 5
  std::unique_ptr<int> a(new int(5));
  std::unique_ptr<int> b{new int(5)};
}
{ // Example 6
  std::locale::global(std::locale("")); // copied from 22.4.8.3
  std::locale::global(std::locale{""});
}
{ // Example 7
  std::default_random_engine a {}; // Stroustrup's FAQ
  std::default_random_engine b;
}
{ // Example 8
  duration<long> a = 5; // Stroustrup's FAQ too
  duration<long> b(5);
  duration<long> c {5};
}

প্রতিটি ঘোষিত ভেরিয়েবলের জন্য, আমাকে ভাবতে হবে যে আমার কোন সিনট্যাক্সটি আরম্ভ করা উচিত এবং এটি আমার কোডিংয়ের গতি কমিয়ে দেয় slow আমি নিশ্চিত যে এটি কোঁকড়া বন্ধনী প্রবর্তন করার উদ্দেশ্য ছিল না।

যখন টেম্পলেট কোডের কথা আসে তখন বাক্য গঠন পরিবর্তন করলে বিভিন্ন অর্থ হতে পারে, সুতরাং সঠিক পথে যাওয়া জরুরি essential

আমি ভাবছি যে কোনও সার্বজনীন গাইডলাইন রয়েছে যা কোন সিনট্যাক্সটি বেছে নেওয়া উচিত।


4
}} সূচনা থেকে অনিচ্ছাকৃত আচরণের উদাহরণ: স্ট্রিং (50, 'x') বনাম স্ট্রিং {50, 'x'} এখানে
পি i

উত্তর:


65

আমি মনে করি নিম্নলিখিতটি একটি ভাল গাইডলাইন হতে পারে:

  • আপনি যে (একক) মানটির সাথে আরম্ভ করছেন তা যদি অবজেক্টের সঠিক মান হিসাবে লক্ষ্য করা যায় তবে অনুলিপি ( =) সূচনা ব্যবহার করুন (কারণ ত্রুটির ক্ষেত্রে আপনি কখনও দুর্ঘটনাক্রমে কোনও স্পষ্ট নির্মাতাকে আবেদন করতে পারবেন না, যা সাধারণত প্রদত্ত মানটিকে ব্যাখ্যা করে ভিন্নভাবে)। যে জায়গাগুলিতে অনুলিপি প্রারম্ভিক উপলব্ধ নেই, সেখানে বন্ধনী সূচনাটির সঠিক শব্দার্থবিজ্ঞান আছে কিনা তা দেখুন এবং যদি তাই হয় তবে এটি ব্যবহার করুন; অন্যথায় প্রথম বন্ধনী ব্যবহার করুন (এটি যদি উপলভ্য না হয় তবে আপনার ভাগ্যের বাইরে নেই)।

  • আপনি যে মানগুলির সাথে আরম্ভ করছেন তা হ'ল অবজেক্টে সংরক্ষণের মানগুলির তালিকা (যেমন কোনও ভেক্টর / অ্যারের উপাদানগুলি, বা কোনও জটিল সংখ্যার আসল / কাল্পনিক অংশ), যদি পাওয়া যায় তবে কোঁকড়া ধনুর্বন্ধনী আরম্ভ করুন।

  • আপনি যে মানগুলির সাথে আরম্ভ করছেন তা যদি সংরক্ষণের মান না হয় তবে অবজেক্টের উদ্দেশ্য মান / অবস্থা বর্ণনা করে, বন্ধনী ব্যবহার করুন। উদাহরণগুলি হ'ল একটি এর আকার যুক্তি vectorবা ফাইল নাম আর্গুমেন্ট fstream


4
@ ব্যবহারকারী1304032: একটি লোকেল কোনও স্ট্রিং নয়, সুতরাং আপনি অনুলিপিটি অনুলিপি ব্যবহার করবেন না। কোনও লোকালে স্ট্রিংও থাকে না (এটি স্ট্রিংটি বাস্তবায়নের বিশদ হিসাবে সংরক্ষণ করতে পারে তবে এটি এর উদ্দেশ্য নয়), সুতরাং আপনি ব্রেস আরম্ভকরণ ব্যবহার করবেন না। সুতরাং নির্দেশিকাটি প্রথম বন্ধনী ব্যবহারের কথা বলে।
celtschk

4
আমি ব্যক্তিগতভাবে এই গাইডলাইনটি বেশিরভাগ ক্ষেত্রে পছন্দ করেছি এবং এটি জেনেরিক কোডেও দুর্দান্ত কাজ করে। কিছু ব্যতিক্রম রয়েছে ( T {}বা সর্বাধিক ভেক্সিং পার্সের মতো সিন্ট্যাকটিক কারণ ) তবে সাধারণভাবে আমি মনে করি এটি একটি ভাল পরামর্শ দেয়। নোট করুন যে এটি আমার বিষয়গত মতামত, তাই অন্যের উত্তরগুলির দিকেও নজর রাখা উচিত।
হেলামি

4
@ এসলেটস্ক্ক: এটি অনুলিপিযোগ্য, অ-অচলিত ধরণের জন্য কাজ করবে না; type var{};করে
iljarn

4
@ এসলেটস্ক্ক: আমি বলছি না যে এটি এমন কিছু যা ঘন ঘন ঘটে থাকে, তবে এটি টাইপিং কম এবং আরও প্রসঙ্গে কাজ করে, তাই ক্ষতি কী?
iljarn

4
আমার নির্দেশিকাগুলি অবশ্যই অনুলিপি করার জন্য কখনই ডাকে না। ; -]
iljarn

27

আমি নিশ্চিত যে এখানে কোনও সর্বজনীন গাইডলাইন থাকবে না। আমার দৃষ্টিভঙ্গি সর্বদা কোঁকড়ানো ধনুর্বন্ধনী স্মরণ করে এটি ব্যবহার করা

  1. ইনিশিয়ালাইজার লিস্ট কনস্ট্রাক্টররা অন্য কনস্ট্রাক্টরের চেয়ে বেশি গুরুত্ব পান
  2. সমস্ত স্ট্যান্ডার্ড লাইব্রেরি পাত্রে এবং স্ট্যান্ড :: বেসিক_স্ট্রিংয়ের ইনিশিয়ালাইজার তালিকার কনস্ট্রাক্টর রয়েছে।
  3. কোঁকড়া ধনুর্বন্ধনী প্রারম্ভিকরণ সংকীর্ণ রূপান্তর অনুমতি দেয় না।

সুতরাং বৃত্তাকার এবং কোঁকড়া ধনুর্বন্ধনী বিনিময়যোগ্য নয়। তবে কোথায় তারা পৃথক রয়েছে তা জানার ফলে বেশিরভাগ ক্ষেত্রে (আমি বর্তমানে যেগুলি সংকলক বাগগুলি পারি না এমন কয়েকটি ক্ষেত্রে) বৃত্তাকার বন্ধনী আরম্ভের জন্য আমাকে কোঁকড়া ব্যবহার করতে দেয়।


7
কোঁকড়া ধনুর্বন্ধনী এর অসুবিধা রয়েছে যা আমি ভুল করে তালিকাটি নির্মাণকারীকে কল করতে পারি। বৃত্তাকার বন্ধনী না। এটি কি ডিফল্টরূপে বৃত্তাকার বন্ধনী ব্যবহার করার কারণ নয়?
হেলামি

4
@ ব্যবহারকারী: int i = 0;আমি মনে করি না যে কেউ সেখানে ব্যবহার int i{0}করবে, এবং এটি বিভ্রান্তিকর হতে পারে (এটিও 0যদি টাইপ হয় তবে সংকীর্ণতাint হবে না )। অন্য কিছুর জন্য, আমি জুয়ানচোর পরামর্শটি অনুসরণ করব: {{পছন্দ করুন, কয়েকটি ক্ষেত্রে আপনার সতর্কতা অবলম্বন করুন। মনে রাখবেন যে প্রচুর ধরণের প্রারম্ভিক সংস্থাগুলি কনস্ট্রাক্টর আর্গুমেন্ট হিসাবে নেবে না, আপনি ধারক এবং ধারক-জাতীয় প্রকারের (টিপল ...) পেতে আশা করতে পারেন, তবে বেশিরভাগ কোডই উপযুক্ত কনস্ট্রাক্টরকে কল করবে।
ডেভিড রদ্রিগেজ - ড্রিবিস

4
@ ব্যবহারকারী1304032 এটি সংকীর্ণ করার বিষয়ে যত্নশীল হলে এটি নির্ভর করে। আমি করি তাই আমি int i{some floating point}চুপ করে কেটে ফেলার পরিবর্তে আমাকে সংকলকটি পছন্দ করেছিলাম যে এটি একটি ত্রুটি।
janchopanza

4
"পছন্দ করুন Con Con সম্পর্কিত, কয়েকটি ক্ষেত্রে সাবধান থাকুন যেখানে আপনার উচিত হবে না": বলুন দুটি শ্রেণীর কাছে শব্দার্থগত সমতুল্য নির্মাতা রয়েছে তবে একটি শ্রেণির একটি প্রাথমিকের তালিকাও রয়েছে। দুই সমতুল্য নির্মাতাকে আলাদা আলাদা বলা উচিত?
হেলামি

4
@ হেলামি: "বলুন দুটি ক্লাসের শব্দার্থগত সমতুল্য কনস্ট্রাক্টর রয়েছে তবে একটি শ্রেণির একটি প্রাথমিকের তালিকাও রয়েছে। দুটি সমমানের কনস্ট্রাক্টরকে আলাদা আলাদা বলা উচিত?" বলুন যে আমি সবচেয়ে বিরক্তিকর পার্সে চলেছি; যে কোনও উদাহরণের জন্য যে কোনও নির্মাণে ঘটতে পারে । {}আপনি একেবারে না পারলে যদি আপনি কেবল "আরম্ভ" বলতে চাইছেন তবে এটি এড়ানো এটি আরও সহজ ।
নিকল বোলাস

16

জেনেরিক কোডের বাইরে (যেমন টেমপ্লেট), আপনি সর্বত্র ব্রেস ব্যবহার করতে পারেন (এবং আমি করব) । একটি সুবিধা হ'ল এটি সর্বত্র কাজ করে, উদাহরণস্বরূপ এমনকি ইন-ক্লাস শুরুর জন্য:

struct foo {
    // Ok
    std::string a = { "foo" };

    // Also ok
    std::string b { "bar" };

    // Not possible
    std::string c("qux");

    // For completeness this is possible
    std::string d = "baz";
};

অথবা ফাংশন যুক্তিগুলির জন্য:

void foo(std::pair<int, double*>);
foo({ 42, nullptr });
// Not possible with parentheses without spelling out the type:
foo(std::pair<int, double*>(42, nullptr));

ভেরিয়েবলগুলির জন্য আমি স্টাইল T t = { init };বা T t { init };শৈলীর মধ্যে খুব বেশি মনোযোগ দিচ্ছি না , আমি পার্থক্যটি অপ্রয়োজনীয় বলে মনে করি এবং সবচেয়ে খারাপ ফলস্বরূপ কেবল কোনও explicitনির্মাণকারীর অপব্যবহার সম্পর্কে সহায়ক সংকলক বার্তার ফলস্বরূপ ।

এমন ধরণের ক্ষেত্রে যা গ্রহণযোগ্য std::initializer_listতবে স্পষ্টতই কখনও কখনও নির- std::initializer_listনির্মাণকারীদের প্রয়োজন হয় (শাস্ত্রীয় উদাহরণটি হচ্ছে std::vector<int> twenty_answers(20, 42);)। তখন ধনুর্বন্ধনী ব্যবহার না করা ভাল।


যখন জেনেরিক কোড আসে (যেমন টেমপ্লেটগুলিতে) তখন খুব শেষ অনুচ্ছেদে কিছু সতর্কতা উত্থাপন করা উচিত ছিল। নিম্নোক্ত বিবেচনা কর:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T { std::forward<Args>(args)... } }; }

তারপর auto p = make_unique<std::vector<T>>(20, T {});আকার 2 একটি ভেক্টর সৃষ্টি যদি Tউদাঃ হয় intবা আকার বা 20 একটি ভেক্টর যদি Tহয় std::string। এখানে খুব ভুল কিছু চলছে বলে খুব লক্ষণীয় লক্ষণটি হ'ল এখানে এমন কোনও বৈশিষ্ট্য নেই যা আপনাকে এখানে বাঁচাতে পারে (উদাহরণস্বরূপ SFINAE সহ): std::is_constructibleএটি সরাসরি-আরম্ভের শর্তে হয়, যেখানে আমরা ব্রেস-ইনিশালাইজেশন ব্যবহার করি যা প্রত্যক্ষ- আর যদি কোনও নির্মাণকারী std::initializer_listহস্তক্ষেপ না করে থাকে তবেই আরম্ভকরণ ization তেমনি std::is_convertibleকোনও উপকার নেই।

আমি এমন একটি বৈশিষ্ট্য যা এটি সমাধান করতে পারে তা হ্যান্ড রোল করা সম্ভব কিনা তবে আমি তদন্ত করেছি তবে আমি সে সম্পর্কে অতিরিক্ত আশাবাদী নই। যাই হোক না কেন আমি মনে করি না যে আমরা অনেক কিছু মিস করব, আমি মনে করি যে make_unique<T>(foo, bar)নির্মাণের সমতুল্য ফলাফলটি T(foo, bar)খুব স্বজ্ঞাত; বিশেষত যে দেওয়া make_unique<T>({ foo, bar })বেশ বিসদৃশ এবং শুধুমাত্র জ্ঞান করে তোলে যদি fooএবং barএকই ধরনের আছে।

সুতরাং জেনেরিক কোডের জন্য আমি কেবল মান সূচনা (যেমন T t {};বা T t = {};) এর জন্য ধনুর্বন্ধনী ব্যবহার করি যা খুব সুবিধাজনক এবং আমি সি ++ 03 উপায়ে উচ্চতর বলে মনে করি T t = T();অন্যথায় এটি হয় সরাসরি সূচনা সিনট্যাক্স (যেমন T t(a0, a1, a2);), বা কখনও কখনও ডিফল্ট নির্মাণ ( T t; stream >> t;আমার মনে হয় যে একমাত্র ক্ষেত্রে এটি ব্যবহার করা হয়)।

এর অর্থ এই নয় যে সমস্ত ধনুর্বন্ধনী যদিও খারাপ, ফিক্স সহ পূর্ববর্তী উদাহরণটি বিবেচনা করুন:

template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{ return std::unique_ptr<T> { new T(std::forward<Args>(args)...) }; }

এটি এখনও নির্মাণের জন্য ধনুর্বন্ধনী ব্যবহার করে std::unique_ptr<T>, যদিও প্রকৃত প্রকারটি টেম্পলেট প্যারামিটারের উপর নির্ভর করে T


@ ইনটারজয় আমার কয়েকটি উদাহরণের পরিবর্তে স্বাক্ষরবিহীন প্রকারের ব্যবহারের প্রয়োজন হতে পারে, যেমন হয় হয় বা হওয়ার make_unique<T>(20u, T {})জন্য । বিশদ সম্পর্কে খুব নিশ্চিত না। (দ্রষ্টব্য যে আমি প্রত্যক্ষ আরম্ভের তুলনায় ব্রেস আরম্ভের উদাহরণ যেমন নিখুঁত-ফরওয়ার্ডিং ফাংশন সম্পর্কিত প্রত্যাশার উপরেও মন্তব্য করেছি) ব্যাকরণে সদস্য ফাংশন ঘোষণার সাথে অস্পষ্টতা এড়াতে কোনও শ্রেণি সূচনা হিসাবে কাজ করার জন্য নির্দিষ্ট করা হয়নি। Tunsignedstd::stringstd::string c("qux");
লুক ড্যান্টন

@ ইনটারজে আমি প্রথম দফায় আপনার সাথে একমত নই, 8.5.4 তালিকার সূচনা এবং 13.3.1.7 তালিকা-সূচনা দ্বারা সূচনা পরীক্ষা করতে নির্দ্বিধায় বোধ করি সেকেন্ডের জন্য হিসাবে, আপনি (যা সংক্রান্ত আমি যা লিখেছিলেন এ একটি ঘনিষ্ঠ কটাক্ষপাত প্রয়োজন শ্রেণীর আরম্ভের) এবং / অথবা সি ++ ব্যাকরণ (যেমন সদস্য-declarator , যা রেফারেন্স বক্রবন্ধনী-অর-সমান-সূচনাকারী )।
লুক ড্যান্টন

হুম, আপনি ঠিক বলেছেন - আমি আগে জিসিসি 4.5 এর সাথে পরীক্ষা করছিলাম যা দেখে আমি যা বলছিলাম তা নিশ্চিত হয়ে গেছে তবে জিসিসি 4.6 আপনার সাথে একমত নয়। এবং আপনি যে শ্রেণীর সূচনা সম্পর্কে কথা বলছিলেন তা আমি মিস করি না। আমার ক্ষমা।
ইন্টারজয়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.