শৃঙ্খলিত করার সময় এলিডি কপি কীভাবে করবেন?


10

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

class test_class {
    private:
    int i = 5;
    public:
    test_class(int i) : i(i) {}
    test_class(const test_class& t) {
        i = t.i;
        std::cout << "Copy constructor"<< std::endl;
    }
    test_class(test_class&& t) {
        i = t.i;
        std::cout << "Move constructor"<< std::endl;
    }
    auto& increment(){
        i++;
        return *this;
    }
};
int main()
{
    //test_class a{7};
    //does not call copy constructor
    auto b = test_class{7};
    //calls copy constructor
    auto b2 = test_class{7}.increment();
    return 0;
}

সম্পাদনা: কিছু স্পষ্টতা। 1. এটি অপ্টিমাইজেশন স্তরের উপর নির্ভর করে না। ২. আমার আসল কোডে আমার কাছে ইনটসের চেয়ে আরও জটিল (উদার হিপ বরাদ্দ) অবজেক্ট রয়েছে


সংকলনের জন্য আপনি কোন অপ্টিমাইজেশন স্তরটি ব্যবহার করেন?
জেভিএপেন

2
auto b = test_class{7};অনুলিপি নির্মাণকারীকে কল দেয় না কারণ এটি সত্যই সমতুল্য test_class b{7};এবং সংকলকরা এই কেসটি সনাক্ত করতে যথেষ্ট স্মার্ট এবং তাই সহজেই কোনও অনুলিপি এলিডে রাখতে পারে। একই জন্য করা যায় না b2
কিছু প্রোগ্রামার ড্যুড

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

উদাহরণটি সংকলিত দেখাচ্ছে looks std::coutআপনার অনুলিপি কর্টারে আসলে আপনার কাছে কি I / O ( ) আছে? এটি ছাড়া অনুলিপিটি অপ্টিমাইজ করা উচিত।
rustyx

@ রুস্টিক্স, std :: cout অপসারণ করুন এবং অনুলিপি নির্মাণকারীকে স্পষ্ট করুন। এটি দেখায় যে অনুলিপি এলিজি স্টাড :: কোট নির্ভর নয়।
DDaniel

উত্তর:


7
  1. আংশিক উত্তর (এটি b2স্থানে নির্মাণ করে না , তবে অনুলিপি নির্মাণকে মুভি নির্মাণে রূপান্তর করে): আপনি incrementসম্পর্কিত উদাহরণের মান বিভাগে সদস্য ফাংশনটি ওভারলোড করতে পারেন :

    auto& increment() & {
        i++;
        return *this;
    }
    
    auto&& increment() && {
        i++;
       return std::move(*this);
    }

    এই জন্য

    auto b2 = test_class{7}.increment();

    সরানো-নির্মাণ করতে b2কারণ test_class{7}একটি অস্থায়ী এবং এর &&ওভারলোডtest_class::increment বলা হয়।

  2. সত্যিকারের স্থানের নির্মাণের জন্য (অর্থাত্ মুভ নির্মাণও নয়), আপনি সমস্ত বিশেষ এবং অ-বিশেষ সদস্য ফাংশনগুলিকে constexprসংস্করণে রূপান্তর করতে পারেন । তারপরে, আপনি করতে পারেন

    constexpr auto b2 = test_class{7}.increment();

    এবং আপনাকে অর্থ প্রদানের জন্য কোনও পদক্ষেপ বা অনুলিপি নির্মাণও করতে হবে না। এটি স্পষ্টতই, সহজটির পক্ষে সম্ভব test_class, তবে এমন আরও সাধারণ দৃশ্যের জন্য নয় যা constexprসদস্যের কার্যকারিতা মঞ্জুর করে না ।


দ্বিতীয় বিকল্পটি b2অ-সংশোধনযোগ্যও করে।
কিছু প্রোগ্রামার ড্যুড

1
পছন্দ করুন আমার ধারণা constinitসেখানে যাওয়ার উপায় হবে।
lubgr

ফাংশন নামের পরে অ্যাম্পারস্যান্ডসের উদ্দেশ্য কী? আমি এর আগে কখনও দেখিনি।
ফিলিপ নেলসন

1
ফিলিপ নেলসন তারা রেফ-কোয়ালিফায়ার এবং সদস্য ফাংশনগুলির thisমতোই কি তা নির্ধারণ করতে constপারে
কিমিড্রেকো

1

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


সহজ উপায়টি হ'ল সম্ভবত অনুলিপিটি প্রস্তুতকারকের সম্পূর্ণরূপে অপ্টিমাইজ করা হচ্ছে। সংকলকটির দ্বারা মান সেটিংটি ইতিমধ্যে অনুকূলিত হয়েছে, এটি কেবলমাত্র std::coutঅপটিমাইজ করা যায় না।

test_class(const test_class& t) = default;

(বা কেবল অনুলিপি এবং সরান কনস্ট্রাক্টর উভয়ই সরিয়ে দিন)

সরাসরি উদাহরণ


যেহেতু আপনার সমস্যাটি প্রাথমিকভাবে রেফারেন্সের সাথে রয়েছে তাই আপনি যদি এইভাবে অনুলিপি করা বন্ধ করতে চান তবে কোনও সমাধান সম্ভবত অবজেক্টের কোনও রেফারেন্স ফিরিয়ে দিচ্ছে না।

  void increment();
};

auto b = test_class{7};//does not call copy constructor
b.increment();//does not call copy constructor

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

auto b2 = []{test_class tmp{7}; tmp.increment().increment().increment(); return tmp;}(); //<-- b2 becomes 10 - copy constructor not called

পরিবর্তে একটি চতুর্থ পদ্ধতিটি একটি পদক্ষেপ ব্যবহার করছে, হয় স্পষ্টভাবে আহ্বান জানানো

auto b2 = std::move(test_class{7}.increment());

বা এই উত্তরে দেখা হিসাবে ।


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