স্ট্রাক্ট এবং স্টাডি :: জোড়া ব্যবহারের মধ্যে পার্থক্য কী?


26

আমি সীমিত অভিজ্ঞতার সাথে একজন সি ++ প্রোগ্রামার।

মনে করুন আমি STL mapকিছু ডেটা সঞ্চয় এবং পরিচালনা করতে একটি ব্যবহার করতে চাই, আমি জানতে চাই যে এই 2 ডেটা কাঠামোর পদ্ধতির মধ্যে কোনও অর্থপূর্ণ পার্থক্য রয়েছে (পারফরম্যান্সেও):

Choice 1:
    map<int, pair<string, bool> >

Choice 2:
    struct Ente {
        string name;
        bool flag;
    }
    map<int, Ente>

বিশেষত, কোনও সাধারণের structপরিবর্তে কোনও ওভারহেড ব্যবহার করছে pair?


18
একটি std::pair হল একটি struct।
কালেথ

3
@ গ্যানাট: এর মতো সাধারণ প্রশ্নগুলি এর মতো নির্দিষ্ট প্রশ্নের ক্ষেত্রে খুব কমই উপযুক্ত দুপ টার্গেট, বিশেষত যদি নির্দিষ্ট উত্তরটি দ্বাপের লক্ষ্যমাত্রায় উপস্থিত না থাকে (যা এই ক্ষেত্রে সম্ভাবনা নেই)।
রবার্ট হার্ভে

18
@ ক্যালথ - std::pairএটি একটি টেমপ্লেটstd::pair<string, bool>একটি কাঠামো।
পিট বেকার

4
pairসম্পূর্ণ শব্দার্থবিজ্ঞান থেকে বঞ্চিত। আপনার কোড (ভবিষ্যতে আপনাকে অন্তর্ভুক্ত) পড়া কেউই জানতে পারবে না যে e.firstআপনি এটি পরিষ্কারভাবে উল্লেখ না করা পর্যন্ত এটি কোনও কিছুর নাম। আমি এর প্রতি pairদৃ poor ় বিশ্বাসী যে এটি একটি খুব দরিদ্র এবং অলস সংযোজন stdছিল এবং এটি যখন ধারণা করা হয়েছিল তখন কেউ ভাবেনি "তবে কিছুদিন, প্রত্যেকে এটি দুটি জিনিস হিসাবে সমস্ত কিছুতে ব্যবহার করবে এবং কারও কোডের অর্থ কী তা কেউ জানতে পারবে না" "।
জেসন সি

2
@ সোনমান ওহ, অবশ্যই তবুও, এটি খুব খারাপ জিনিস যেমন mapপুনরাবৃত্তি বৈধ ব্যতিক্রম নয়। ("প্রথম" = কী এবং "দ্বিতীয়" = মান ... সত্যিই std?? সত্যই?)
জেসন সি

উত্তর:


33

পছন্দ 1 ছোট "শুধুমাত্র একবার ব্যবহৃত" জিনিসগুলির জন্য ঠিক। মূলত std::pairএখনও একটি কাঠামো। এই মন্তব্যের মাধ্যমে পছন্দ হিসাবে বলা হয়েছে 1 খরগোশের গর্তের মতো কোথাও কোথাও সত্যিই কুৎসিত কোডের দিকে নিয়ে যাবে thing.second->first.second->secondএবং কেউ সত্যই এটি বোঝাতে চায় না।

পছন্দ 2 অন্য সমস্ত কিছুর জন্য ভাল, কারণ মানচিত্রে জিনিসগুলির অর্থ কী তা পড়া সহজ। আপনি যদি ডেটা পরিবর্তন করতে চান তবে এটি আরও নমনীয় (উদাহরণস্বরূপ যখন এন্টে হঠাৎ করে অন্য পতাকা লাগবে)। পারফরম্যান্স এখানে সমস্যা হওয়া উচিত নয়।


15

পারফরম্যান্স :

এটা নির্ভর করে.

আপনার বিশেষ ক্ষেত্রে কোনও পারফরম্যান্সের পার্থক্য থাকবে না কারণ দু'জন একইভাবে মেমরির মধ্যে রাখা হবে।

খুব নির্দিষ্ট ক্ষেত্রে (যদি আপনি কোনও ডেটা সদস্য হিসাবে খালি কাঠামো ব্যবহার করে থাকেন ) তবে std::pair<>খালি বেস অপটিমাইজেশন (ইবিও) সম্ভাব্যভাবে ব্যবহার করতে পারে এবং কাঠামোর সমতুলের চেয়ে কম আকার থাকতে পারে। এবং নিম্ন আকারের অর্থ উচ্চতর কর্মক্ষমতা:

struct Empty {};
struct Thing { std::string name; Empty e; };

int main() {
    std::cout << sizeof(std::string) << "\n";
    std::cout << sizeof(std::tuple<std::string, Empty>) << "\n";
    std::cout << sizeof(std::pair<std::string, Empty>) << "\n";
    std::cout << sizeof(Thing) << "\n";
}

মুদ্রণ: 32, 32, 40, 40 আইডোনে

দ্রষ্টব্য: আমি এমন কোনও বাস্তবায়ন সম্পর্কে অবগত নই যিনি আসলে নিয়মিত জোড়গুলির জন্য EBO কৌশল ব্যবহার করেন, তবে এটি সাধারণত টিপলসের জন্য ব্যবহৃত হয়।


পঠনযোগ্যতা :

মাইক্রো-অপটিমাইজেশন ছাড়াও, একটি নামক কাঠামোটি আরও অ্যারগোনমিক।

আমি বলতে চাইছি, সবেমাত্র বুদ্ধিমান হওয়ার map[k].firstসময়ও এটি খারাপ নয় get<0>(map[k])। এর বিপরীতে map[k].nameযা তাত্ক্ষণিকভাবে নির্দেশ করে যে আমরা কী থেকে পড়ছি।

প্রকারভেদগুলি একে অপরের সাথে রূপান্তরিত হওয়ার পরে এটি আরও গুরুত্বপূর্ণ, যেহেতু অজান্তে সেগুলি অদলবদল করা একটি সত্যিকারের উদ্বেগ হয়ে যায়।

আপনি স্ট্রাকচারাল বনাম নমিনাল টাইপিং সম্পর্কেও পড়তে চাইতে পারেন। Enteএটি একটি নির্দিষ্ট ধরণের যা কেবল প্রত্যাশিত জিনিসগুলির দ্বারা চালিত হতে পারে Ente, যে কোনও কিছু যা পরিচালনা std::pair<std::string, bool>করতে পারে সেগুলি তাদের উপর পরিচালনা করতে পারে ... এমনকি যখন তারা যা প্রত্যাশা করে না std::stringবা boolধারণ করে না, কারণ এর std::pairসাথে কোনও শব্দার্থবিজ্ঞান নেই ।


রক্ষণাবেক্ষণ :

রক্ষণাবেক্ষণের ক্ষেত্রে, pairসবচেয়ে খারাপ। আপনি কোনও ক্ষেত্র যোগ করতে পারবেন না।

tupleএই ক্ষেত্রে মেলা আরও ভাল, যতক্ষণ না আপনি নতুন ক্ষেত্রটি যুক্ত করেন ততক্ষণে বিদ্যমান বিদ্যমান ক্ষেত্রগুলি একই সূচক দ্বারা অ্যাক্সেস করা যায়। যা পূর্বের মতো অনির্বচনীয় তবে কমপক্ষে আপনাকে এগুলি আপডেট করার দরকার নেই।

structস্পষ্ট বিজয়ী। আপনি যেখানে মনে করেন ক্ষেত্রগুলি যুক্ত করতে পারেন।


উপসংহারে:

  • pair উভয় বিশ্বের সবচেয়ে খারাপ,
  • tuple খুব নির্দিষ্ট ক্ষেত্রে (খালি টাইপ) এর সামান্য প্রান্ত থাকতে পারে,
  • ব্যবহারstruct

দ্রষ্টব্য: আপনি যদি গেটারগুলি ব্যবহার করেন তবে ক্লায়েন্টদের এটি সম্পর্কে যেমন না জেনে আপনি খালি বেস ট্রিকটি নিজেই ব্যবহার করতে পারেন struct Thing: Empty { std::string name; }; এ কারণেই এনক্যাপসুলেশন হ'ল পরবর্তী বিষয় যা আপনার নিজের উচিত concern


3
আপনি জোড়গুলির জন্য ইবিও ব্যবহার করতে পারবেন না, যদি আপনি মান অনুসরণ করেন following জোড়ার উপাদানগুলি সদস্যদের মধ্যে সংরক্ষণ করা হয় firstএবং secondখালি বেস অপ্টিমাইজেশনের জন্য আর কোনও জায়গা নেই
রিভলবার_অসেলোট

2
@ রিভলবার_সেলোট: আচ্ছা, আপনি এমন একটি সি ++ লিখতে পারবেন না যা EBO pairব্যবহার করবে তবে একটি সংকলক বিল্ট-ইন সরবরাহ করতে পারে। যেহেতু এগুলি সদস্য হওয়ার কথা, তবে এটি পর্যবেক্ষণযোগ্য হতে পারে (তাদের ঠিকানাগুলি পরীক্ষা করা, উদাহরণস্বরূপ) কোন ক্ষেত্রে এটি অনুসারে কাজ করবে না।
ম্যাথিউ এম।

1
সি ++ ২০ যোগ করে [[no_unique_address]], যা সদস্যদের জন্য ইবিওর সমতুল্যকে সক্ষম করে।
আন্ডারস্কোর_ দিন

3

স্টার্ড :: টাই এবং সি ++ 17 এর স্ট্রাকচার্ড বাইন্ডিং ব্যবহার করে ডেস্ট্রাকচার্ড অ্যাসাইনমেন্টের সাথে ফাংশনের রিটার্ন টাইপ হিসাবে যুক্ত হয়ে সবচেয়ে বেশি জুড়ি থাকে। স্ট্যান্ড :: টাই ব্যবহার:

struct Ente {/*...*/};
std::map<int, Ente> map;
auto inserted_position = map.end();
auto was_inserted = false;
std::tie(inserted_position, was_inserted) = map.emplace(1, Ente{});
if (!was_inserted) {
    //handle insertion error
}

সি ++ 17 এর স্ট্রাকচার্ড বাইন্ডিং ব্যবহার করে:

struct Ente {/*...*/};
std::map<int, Ente> map;
auto [inserted_position, was_inserted] = map.emplace(1, Ente{});
if (!was_inserted) {
    //handle insertion error
}

স্টাড :: জোড় (বা টিপল) এর ব্যবহারের খারাপ উদাহরণটি এরকম কিছু হবে:

using player_data = std::tuple<std::string, uint64_t, double>;
player_data player{};
/* ... */
auto health = std::get<2>(player);
/* ... */

কারণ স্টাডিকে কল করার সময় এটি স্পষ্ট নয়: পজিশন সূচীতে কী সঞ্চিত আছে <<> (প্লেয়ার_ডাটা) পান read মনে রাখবেন পাঠযোগ্যতার কথা মনে করুন এবং কোডটি কী করছে তা পাঠকের পক্ষে তা স্পষ্ট করে দেওয়া গুরুত্বপূর্ণ । বিবেচনা করুন যে এটি আরও বেশি পাঠযোগ্য:

struct player_data
{
    std::string name;
    uint64_t player_id;
    double current_health;
};
player_data player{};
/* ... */
auto health = player.current_health;
/* ... */

কোনও ফাংশন থেকে 1 টিরও বেশি অবজেক্ট ফেরত পাওয়ার উপায় হিসাবে আপনাকে সাধারণত স্টাড :: জোড় এবং এসটিডি :: টিপল সম্পর্কে ভাবা উচিত। আমি যে থাম্বের নিয়ম ব্যবহার করি (এবং আরও অনেকের পাশাপাশি এটি ব্যবহার করতেও দেখেছি) সে নিয়মটি হ'ল যে স্টাডেন্ট :: টিপল বা স্টাডি :: পেয়ারে ফিরে আসা বস্তুগুলি কেবল কোনও ফাংশনে কল দেওয়ার প্রসঙ্গে কেবল "সম্পর্কিত" যা তাদের ফেরত দেয় বা ডেটা স্ট্রাকচারের প্রসঙ্গে যা এগুলি একসাথে লিঙ্ক করে (যেমন স্টাড :: মানচিত্র তার স্টোরেজ ধরণের জন্য স্টাডি :: পেয়ার ব্যবহার করে)। যদি সম্পর্কটি আপনার কোডটিতে অন্য কোথাও বিদ্যমান থাকে তবে আপনার স্ট্রাক ব্যবহার করা উচিত।

মূল গাইডলাইন সম্পর্কিত বিভাগসমূহ:

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.