সি ++ 11 এ কোন প্রকারকে অচল অস্থাবর কখন করবেন?


126

আমি আমার অনুসন্ধানের ফলাফলগুলিতে এটি প্রদর্শিত না হয়ে অবাক হয়েছি, আমি ভেবেছিলাম যে সি ++ 11 তে পদক্ষেপ পদার্থের দক্ষতাটি দেখে কেউ আগে এটি জিজ্ঞাসা করেছিল:

আমার কখন (বা এটি আমার পক্ষে ভাল ধারণা) সি ++ 11 এ অবিচলিত বর্গ তৈরি করতে হবে?

( বিদ্যমান কোডের সাথে সামঞ্জস্যতা ইস্যু ছাড়া অন্য কারণগুলি ,)


2
বুস্ট সর্বদা এক ধাপ এগিয়ে - "প্রকারভেদে সরানো ব্যয়বহুল" ( boost.org/doc/libs/1_48_0/doc/html/container/move_emplace.html )
শেচেপুরিন

1
আমি মনে করি এটি একটি খুব ভাল এবং দরকারী প্রশ্ন ( +1আমার কাছ থেকে) ভেষজ (বা তার যমজ, যেমনটি মনে হচ্ছে ) এর একটি খুব ভাল উত্তর সহ , তাই আমি এটিকে এফএকিউ এন্ট্রি করেছিলাম। কেউ যদি কেবলমাত্র লাউঞ্জে আমাকে পিং করে তোলে তবে এটি এখানে আলোচনা করা যেতে পারে।
এসবিআই

1
আফাইক চলমান ক্লাসগুলি এখনও কাটানোর মতো হতে পারে, সুতরাং এটি সমস্ত পলিমারফিক বেস ক্লাসের (যেমন ভার্চুয়াল ফাংশন সহ সমস্ত বেস ক্লাস) চলন্ত (এবং অনুলিপি) নিষিদ্ধ করার অর্থ বোধ করে।
ফিলিপ

1
@ মেহরদাদ: আমি শুধু বলছি যে "টিতে একটি মুভ কনস্ট্রাক্টর রয়েছে" এবং " T x = std::move(anotherT);আইনী হওয়া" সমতুল্য নয়। দ্বিতীয়টি মুভ-রিকোয়েস্ট যা টি-তে কোনও মুভ সিটার না থাকলে কপির অন্বেষণে ফিরে যেতে পারে। সুতরাং, "অস্থাবর" এর অর্থ কী?
বিক্রয়বিটজে

1
@ মেহরদাদ: "মুভ কনস্ট্রাক্টেবল" এর অর্থ সি ++ স্ট্যান্ডার্ড লাইব্রেরি বিভাগটি দেখুন। কিছু পুনরাবৃত্তির কাছে মুভ কনস্ট্রাক্টর নাও থাকতে পারে তবে এটি এখনও মুভকনস্ট্রেকটেবল। "চলমান" লোকেদের মনে যে বিবিধ সংজ্ঞা রয়েছে তা দেখুন।
বিক্রয়বিটজে

উত্তর:


110

ঔষধি এর উত্তর (আগেই সম্পাদিত হয়েছে) প্রকৃতপক্ষে একটি টাইপ যা একটি ভাল উদাহরণ দিলেন করা উচিত নয় অস্থাবর হতে: std::mutex

ওএসের নেটিভ মিটেক্স টাইপ (যেমন pthread_mutex_tপসিক্স প্ল্যাটফর্মগুলিতে) "অবস্থানের আক্রমণকারী" নাও হতে পারে যার অর্থ বস্তুর ঠিকানা তার মানটির অংশ of উদাহরণস্বরূপ, ওএস সমস্ত প্রারম্ভিক মুটেক্স অবজেক্টের পয়েন্টারগুলির একটি তালিকা রাখতে পারে। যদি std::mutexকোনও ডেটা সদস্য হিসাবে একটি নেটিভ ওএস মিউটেক্স টাইপ থাকে এবং নেটিভ টাইপের ঠিকানা অবশ্যই স্থির থাকে (কারণ ওএস তার মিউটেক্সগুলিতে পয়েন্টারগুলির একটি তালিকা বজায় রাখে) তবে হয় std::mutexনেটিভ মিটেক্স টাইপটি গাদাতে সংরক্ষণ করতে হবে যাতে এটি স্থির থাকে would std::mutexবস্তুগুলির মধ্যে স্থানান্তরিত করার সময় একই অবস্থান বা নড়াচড়া করতে std::mutexহবে না। এটি স্তূপে সংরক্ষণ করা সম্ভব নয়, কারণ একজনের std::mutexএকজন constexprকনস্ট্রাক্টর রয়েছে এবং অবশ্যই ধ্রুবক সূচনা (যেমন স্ট্যাটিক ইনিশিয়ালাইজেশন) এর জন্য যোগ্য হতে হবে যাতে একটি গ্লোবালstd::mutexপ্রোগ্রামটির সম্পাদন শুরু হওয়ার আগেই নির্মাণের গ্যারান্টিযুক্ত, সুতরাং এর নির্মাণকারী ব্যবহার করতে পারবেন না new। সুতরাং std::mutexঅস্থাবর জন্য একমাত্র বিকল্প বাকি ।

একই যুক্তি অন্যান্য ধরণের ক্ষেত্রেও প্রযোজ্য যার মধ্যে এমন কোনও নির্দিষ্ট ঠিকানা রয়েছে। যদি উত্সের ঠিকানা স্থির থাকতেই হয় তবে তা সরাবেন না!

না সরানোর জন্য আরও একটি যুক্তি রয়েছে std::mutexযা এটি নিরাপদে করা খুব কঠিন হবে কারণ আপনার জানা দরকার যে নুন মুভেক্সকে স্থানান্তরিত করার মুহুর্তে লক করার চেষ্টা করছেন। যেহেতু ডেটা দৌড় প্রতিরোধের জন্য মুটেক্সগুলি আপনি যে বিল্ডিং ব্লকগুলি ব্যবহার করতে পারেন তার মধ্যে একটি হ'ল, যদি তারা নিজেরাই ঘোড়দৌড়ের বিরুদ্ধে সুরক্ষিত না হত তবে দুর্ভাগ্য হবে! একটি অস্থাবর সাথে std::mutexআপনি জানেন যে এটি তৈরির পরে এবং এটি ধ্বংস হওয়ার আগে যে কেউ কেবল এটির জন্য কাজ করতে পারে তা হ'ল লক করা এবং আনলক করা এবং সেই ক্রিয়াকলাপগুলি সুস্পষ্টভাবে গ্যারান্টিযুক্ত যে থ্রেড নিরাপদ এবং ডেটা রেসগুলি প্রবর্তন না করে। এই একই যুক্তি std::atomic<T>বস্তুর ক্ষেত্রে প্রযোজ্য : এগুলি এটমিকভাবে স্থানান্তরিত না করা পারলে নিরাপদে তাদের সরানো সম্ভব হত না, অন্য কোনও থ্রেড কল করার চেষ্টা করছেcompare_exchange_strongমুহুর্তে এটি সরানো হচ্ছে ঠিক মুহূর্তে। সুতরাং আর একটি ক্ষেত্রে যেখানে প্রকারগুলি চলনযোগ্য না হওয়া উচিত সেগুলি হল সেগুলি নিরাপদ সমবর্তী কোডের নিম্ন-স্তরের বিল্ডিং ব্লক এবং তাদের উপর সমস্ত ক্রিয়াকলাপের পারমাণবিকতা নিশ্চিত করতে হবে। যদি কোনও সময়ে বস্তুর মান কোনও নতুন অবজেক্টে স্থানান্তরিত হতে পারে তবে প্রতিটি পারমাণবিক পরিবর্তনশীলকে সুরক্ষিত করার জন্য আপনাকে যদি পারমাণবিক পরিবর্তনশীল ব্যবহার করতে হবে তবে আপনি জানতে পারবেন এটি ব্যবহার করা নিরাপদ কিনা বা স্থানান্তরিত হয়েছে কিনা ... এবং একটি পরমাণু পরিবর্তনশীল রক্ষা করতে যে পারমাণবিক পরিবর্তনশীল, এবং আরও ...

আমি মনে করি আমি সাধারণভাবে এটি বলতে চাই যে যখন কোনও বস্তু কেবল মেমরির খাঁটি অংশ হয় তবে এমন কোনও ধরণের নয় যা কোনও মান বা মূল্যকে বিমূর্ত করার জন্য ধারক হিসাবে কাজ করে, এটি স্থানান্তরিত করার কোনও মানে হয় না। মৌলিক ধরণের যেমন intচলতে পারে না: এগুলি সরিয়ে নেওয়া কেবল একটি অনুলিপি। আপনি একটি থেকে সাহস ছিঁড়ে ফেলতে পারবেন না int, আপনি এর মানটি অনুলিপি করতে পারেন এবং তারপরে এটি শূন্যতে সেট করতে পারেন, তবে এটি এখনও intএকটি মান সহ একটি, এটি কেবল মেমরির বাইট। তবে একটি intএখনও অস্থাবরভাষার পদগুলিতে কারণ একটি অনুলিপি একটি বৈধ পদক্ষেপ অপারেশন। অনুলিপিযোগ্য প্রকারের জন্য, আপনি যদি না চান বা মেমরির অংশটি সরাতে না পারেন এবং আপনি এর মানটিও অনুলিপি করতে পারবেন না, তবে এটি অচল। একটি মিউটেক্স বা পারমাণবিক পরিবর্তনশীল মেমরির একটি নির্দিষ্ট অবস্থান (বিশেষ বৈশিষ্ট্যযুক্ত) এটি স্থানান্তরিত করার কোনও অর্থ দেয় না, এবং অনুলিপিযোগ্যও নয়, সুতরাং এটি অচল।


17
স্থানান্তরিত করা যায় না এমন কোনও কিছুর কম বিদেশী উদাহরণ +1 করা কারণ এটির একটি নির্দিষ্ট ঠিকানা রয়েছে নির্দেশিত গ্রাফ কাঠামোর একটি নোড।
পোটোসওয়টার

3
যদি মিউটেক্স অ-অনুলিপিযোগ্য এবং অ-অচল অযোগ্য হয় তবে আমি কীভাবে এমন কোনও বস্তু অনুলিপি করতে বা সরিয়ে নিতে পারি যার মধ্যে একটি মিউটেক্স রয়েছে? (সিঙ্ক্রোনাইজেশনের জন্য এটি নিজস্ব
মুটেক্স

4
@ ট্রিনিডব্লিউ, আপনি পারবেন না, যদি না আপনি স্তূপে মিটেক্স তৈরি করেন এবং এটি কোনও অনন্য_পিটার বা অনুরূপের মাধ্যমে ধরে না রাখেন
জোনাথন

2
@ tr3w: আপনি কেবল মিটেক্স অংশটি বাদ দিয়ে পুরো ক্লাসটি সরান না ?
ব্যবহারকারী541686

3
@ বেনভয়েগ্ট, তবে নতুন অবজেক্টটির নিজস্ব মিউটেক্স থাকবে। আমি মনে করি তার অর্থ ব্যবহারকারী সংজ্ঞায়িত পদক্ষেপ অপারেশন যা মুটেক্স সদস্য ব্যতীত সমস্ত সদস্যকে সরিয়ে দেয়। তাহলে কি যদি পুরাতন বস্তুর মেয়াদ শেষ হয়? এটির সাথে এর মিটেক্সের মেয়াদ শেষ হয়।
জোনাথন ওয়াকলি

57

সংক্ষিপ্ত উত্তর: কোনও প্রকার যদি অনুলিপিযোগ্য হয় তবে এটি চলনযোগ্যও হওয়া উচিত। তবে, বিপরীতটি সত্য নয়: কিছু প্রকারের মতো std::unique_ptrচলনযোগ্য তবে সেগুলি অনুলিপি করার কোনও অর্থ হয় না; এগুলি প্রাকৃতিকভাবে চালিত-প্রকারের।

সামান্য দীর্ঘ উত্তর অনুসরণ ...

দুটি বড় ধরণের প্রকার রয়েছে (অন্যান্য বিশেষ-উদ্দেশ্যগুলির মধ্যে যেমন বৈশিষ্টগুলি):

  1. মান মতো ধরণের, যেমন intবা vector<widget>। এগুলি মানগুলি উপস্থাপন করে এবং স্বভাবতই অনুলিপিযোগ্য হওয়া উচিত। সি ++ ১১-এ, সাধারণত আপনার অনুলিপিটির অপ্টিমাইজেশন হিসাবে স্থানান্তরিত হওয়ার কথা ভাবা উচিত, এবং তাই সমস্ত অনুলিপিযোগ্য ধরণের স্বাভাবিকভাবেই চলনযোগ্য হওয়া উচিত ... সচরাচর-সাধারণ ক্ষেত্রে অনুলিপি করার অনুলিপি কেবল একটি কার্যকর উপায় ' আর আর আসল অবজেক্টের দরকার নেই এবং এটি যেভাবেই হোক ধ্বংস করতে চলেছে।

  2. উত্তরাধিকারের স্তরক্রমগুলিতে রেফারেন্স-জাতীয় ধরণের উপস্থিতি যেমন ভার্চুয়াল বা সুরক্ষিত সদস্য ফাংশন সহ বেস ক্লাস এবং ক্লাস। এগুলি সাধারণত পয়েন্টার বা রেফারেন্স দ্বারা রাখা হয়, প্রায়শই একটি base*বা base&, এবং তাই টুকরা কাটা এড়ানোর জন্য অনুলিপি নির্মাণ সরবরাহ করে না; আপনি যদি বিদ্যমান কোনটির মতোই অন্য কোনও জিনিস পেতে চান তবে আপনি সাধারণত ভার্চুয়াল ফাংশনটিকে কল করেন clone। এগুলির দুটি কারণে মুভ নির্মাণ বা অ্যাসাইনমেন্টের প্রয়োজন নেই: এগুলি অনুলিপিযোগ্য নয়, এবং ইতিমধ্যে তাদের আরও কার্যকর প্রাকৃতিক "চাল" অপারেশন রয়েছে - আপনি কেবলমাত্র পয়েন্টারটিকে অনুলিপিতে অনুলিপি / সরিয়ে নিয়ে যান এবং অবজেক্টটি নিজেই করেন না একেবারে একটি নতুন মেমরি অবস্থানে যেতে হবে।

বেশিরভাগ প্রকারগুলি এই দুটি বিভাগের মধ্যে একটির মধ্যে পড়ে তবে অন্যান্য ধরণের প্রকারগুলিও দরকারী যা কেবল বিরল। বিশেষত এখানে, এমন ধরণ যা সংস্থানগুলির অনন্য মালিকানা প্রকাশ করে, যেমন std::unique_ptrপ্রাকৃতিকভাবে কেবল চালিত প্রকার, কারণ সেগুলি মান-সমান নয় (এটি অনুলিপি করার কোনও মানে হয় না) তবে আপনি সেগুলি সরাসরি ব্যবহার করেন (সর্বদা নয় পয়েন্টার বা রেফারেন্সের মাধ্যমে) এবং তাই এই ধরণের অবজেক্টগুলিকে এক জায়গা থেকে অন্য জায়গায় নিয়ে যেতে চান।


61
চান বাস্তব ঔষধি Sutter দাঁড়ানো দয়া করে? :)
ফ্রেডওভারফ্লো

6
হ্যাঁ, আমি একটি ওআউথ গুগল অ্যাকাউন্ট অন্যটিতে ব্যবহার করা থেকে সরিয়েছি এবং আমাকে এখানে যে দুটি লগইন একত্রীভূত করার উপায় খুঁজছেন তা বিরক্ত করা যায় না। (আরও বেশি বাধ্যকারীদের মধ্যে ওআউথের বিরুদ্ধে আরও একটি যুক্তি)) আমি সম্ভবত অন্যটিকে আবার ব্যবহার করব না, তাই এখনই আমি এই বিষয়টিকে মাঝে মাঝে এসও পোস্টের জন্য ব্যবহার করব।
ভেষজ সুটার 12

7
আমি ভেবেছিলাম যে std::mutexস্থাবর ছিল, কারণ পসিক্স মুটেক্সগুলি ঠিকানা দ্বারা ব্যবহৃত হয়।
কুকুরছানা

9
@ এস চেপুরিন: আসলে, তখন তাকে বলা হয় হার্বওভারফ্লো।
এসবিআই

26
এটি প্রচুর উদ্দীপনা পাচ্ছে, কেউ কি খেয়াল করে দেখেছেন যে যখন কোনও প্রকারটি কেবল চলনযোগ্য হওয়া উচিত, যা প্রশ্ন নয়? :)
জোনাথন Wakely

18

আসলে যখন আমি আশেপাশে অনুসন্ধান করি তখন আমি দেখতে পেলাম যে বেশ কয়েকটি প্রকারের C ++ 11 অস্থাবর নয়:

  • সব mutexপ্রকার ( recursive_mutex, timed_mutex, recursive_timed_mutex,
  • condition_variable
  • type_info
  • error_category
  • locale::facet
  • random_device
  • seed_seq
  • ios_base
  • basic_istream<charT,traits>::sentry
  • basic_ostream<charT,traits>::sentry
  • সব atomicধরণের
  • once_flag

স্পষ্টতই ঝাঁকুনির বিষয়ে আলোচনা চলছে: https://groups.google.com/forum/?fromgroups=#!topic/comp.std.c++/pCO1Qqb3Xa4


1
... পুনরাবৃত্তকারীদের চলমান হওয়া উচিত নয় ?! কি কেন?
user541686

হ্যাঁ, আমার মনে iterators / iterator adaptorsহয় সি ++ 11 তে মুভি_এটর রয়েছে বলে এটিকে সম্পাদনা করা উচিত?
বিল্জ

ঠিক আছে এখন আমি ঠিক বিভ্রান্ত আপনি কি পুনরাবৃত্তকারীদের সম্পর্কে কথা বলছেন যা তাদের লক্ষ্যগুলি সরিয়ে দেয় , বা পুনরুক্তিকারীদের নিজেরাই সরানোর বিষয়ে ?
user541686

1
তাই হয় std::reference_wrapper। ঠিক আছে, অন্যরা প্রকৃতপক্ষে অচলিত বলে মনে হচ্ছে।
খ্রিস্টান রাউ

1
এই তিনটি শ্রেণীতে পড়া বলে মনে হচ্ছে: 1. নিম্ন স্তরের সম্পাতবিন্দু সংক্রান্ত প্রকার (atomics, mutexes), 2. বহুরুপী বেস ক্লাস ( ios_base, type_info, facet), 3. হরেক রকম অদ্ভুত জিনিস ( sentry)। সম্ভবত একজন গড় অভাবনীয় ক্লাস কেবল একজন গড় প্রোগ্রামার দ্বিতীয় শ্রেণিতে পড়বে।
ফিলিপ

0

আর একটি কারণ আমি খুঁজে পেয়েছি - পারফরম্যান্স। বলুন আপনার একটি ক্লাস 'এ' রয়েছে যার মান রয়েছে। আপনি একটি ইন্টারফেস আউটপুট করতে চান যা ব্যবহারকারীকে সীমিত সময়ের জন্য (একটি সুযোগের জন্য) মান পরিবর্তন করতে দেয়।

এটি অর্জনের একটি উপায় হ'ল 'এ' থেকে 'স্কোপ গার্ড' অবজেক্টটি ফিরিয়ে দেওয়া যা এর ডেস্ট্রাক্টরটিতে মানটি আবার সেট করে:

class a 
{ 
    int value = 0;

  public:

    struct change_value_guard 
    { 
        friend a;
      private:
        change_value_guard(a& owner, int value) 
            : owner{ owner } 
        { 
            owner.value = value;
        }
        change_value_guard(change_value_guard&&) = delete;
        change_value_guard(const change_value_guard&) = delete;
      public:
        ~change_value_guard()
        {
            owner.value = 0;
        }
      private:
        a& owner;
    };

    change_value_guard changeValue(int newValue)
    { 
        return{ *this, newValue };
    }
};

int main()
{
    a a;
    {
        auto guard = a.changeValue(2);
    }
}

যদি আমি পরিবর্তন_মূল্য_গার্ডকে অস্থাবর করে তুলি তবে আমাকে তার ধ্বংসকারীতে একটি 'যদি' যুক্ত করতে হবে যা গার্ডটি স্থানান্তরিত হয়েছে কিনা তা খতিয়ে দেখবে - এটি অতিরিক্ত, এবং পারফরম্যান্সের প্রভাব impact

হ্যাঁ, অবশ্যই, এটি সম্ভবত কোনও বুদ্ধিমান অপ্টিমাইজার দ্বারা অপ্টিমাইজ করা যেতে পারে, তবে তবুও এটি চমৎকার যে ভাষাটির জন্য (এটি সি ++ 17 প্রয়োজন, যদিও একটি অচলিত প্রকারটি ফেরত দিতে সক্ষম হতে গ্যারান্টিযুক্ত অনুলিপি আবশ্যক প্রয়োজন) আমাদের প্রয়োজন হয় না us এটি প্রদান করার জন্য যদি আমরা তৈরির ফাংশনটি থেকে ফেরত দেওয়া ব্যতীত অন্য কোনওভাবে প্রহরীকে সরিয়ে না চলি (আপনাকে কী ব্যবহারের নীতিটি দেবে না)

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