সি ++ প্রফুল্ল অনুলিপি অপারেশনগুলি কীভাবে সন্ধান করবেন?


11

সম্প্রতি, আমি নিম্নলিখিত ছিল

struct data {
  std::vector<int> V;
};

data get_vector(int n)
{
  std::vector<int> V(n,0);
  return {V};
}

এই কোডটির সাথে সমস্যাটি হ'ল যখন স্ট্রাকটি তৈরি করা হবে তখন একটি অনুলিপি উপস্থিত হয় এবং সমাধানটি পরিবর্তে লিখতে হয় {std :: পদক্ষেপ (V) (

এমন কি লিটার বা কোড বিশ্লেষক রয়েছে যা এই জাতীয় জালিয়াতি অনুলিপি অপারেশন সনাক্ত করতে পারে? সিপিচেক, সিপ্লিপিন্ট, বা ঝনঝন পরিশ্রম কেউই এটি করতে পারে না।

সম্পাদনা: আমার প্রশ্ন পরিষ্কার করার জন্য কয়েকটি বিষয়:

  1. আমি জানি যে একটি অনুলিপি অপারেশন ঘটেছে কারণ আমি সংকলক এক্সপ্লোরার ব্যবহার করেছি এবং এটি ম্যাকপিকে একটি কল দেখায় ।
  2. আমি সনাক্ত করতে পারি যে হ্যাঁ মানটি দেখে একটি অনুলিপি অপারেশন হয়েছিল। তবে আমার প্রাথমিক ভুল ধারণাটি ছিল যে সংকলকটি এই অনুলিপিটিকে অপ্টিমাইজ করবে। আমি ভৃল ছিলাম.
  3. এটি (সম্ভবত) একটি সংকলক সমস্যা নয় যেহেতু ঝনঝন এবং জিসিসি উভয়ই কোডগুলি উত্পাদন করে যা একটি মেমকি তৈরি করে
  4. মেমকিপি সস্তা হতে পারে তবে আমি এমন পরিস্থিতিতে কল্পনা করতে পারি না যেখানে মেমরি অনুলিপি করা এবং মূল মুছে ফেলা স্টাডি :: পদক্ষেপের মাধ্যমে পয়েন্টার পাস করার চেয়ে সস্তা ।
  5. এর যোগ এসটিডি :: পদক্ষেপ একটি প্রাথমিক অপারেশন। আমি কল্পনা করব যে কোনও কোড বিশ্লেষক এই সংশোধনটির পরামর্শ দিতে সক্ষম হবেন।

2
"জালিয়াতি" অনুলিপি অপারেশনগুলি সনাক্ত করার জন্য কোনও পদ্ধতি / সরঞ্জাম রয়েছে কিনা তা আমি উত্তর দিতে পারছি না, তবে আমার সৎ মতে আমি এই বিষয়টির সাথে একমত নই যে কোনওভাবেই অনুলিপি std::vectorকরা উচিত নয়, এটির উদ্দেশ্যটি কী । আপনার উদাহরণটি একটি স্পষ্ট অনুলিপি দেখায়, এবং এটি কেবল প্রাকৃতিক এবং সঠিক পদ্ধতির (আবার ইমো) std::moveফাংশনটি প্রয়োগ করা যেমন আপনি নিজের মতামত জানান তবে কোনও অনুলিপি আপনি চান তা যদি না থাকে। নোট করুন যে কয়েকটি সংকলক অপ্টিমাইজেশন পতাকাগুলি চালু করা থাকলে এবং ভেক্টরটি অপরিবর্তিত থাকলে অনুলিপিটি বাদ দিতে পারে।
ম্যাগনাস

আমি আশঙ্কা খুব বেশী অপ্রয়োজনীয় কপি (যা প্রভাবিত না হতে পারে) এই Linter নিয়ম ব্যবহারযোগ্য করতে আছে: - / ( মরিচা ব্যবহারসমূহ ডিফল্টরূপে সরাতে তাই স্পষ্ট কপি প্রয়োজন :))
Jarod42

কোডটি অনুকূলিতকরণের জন্য আমার পরামর্শগুলি মূলত আপনি যে
কার্যটি

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

2
উদ্দীপক অনুলিপিগুলি খুঁজতে আমি যে কৌশলটি ব্যবহার করি তা হ'ল অনুলিপি অনুলিপি নির্মাণকারীকে ব্যক্তিগত করা এবং তারপরে অ্যাক্সেস সীমাবদ্ধতার কারণে কম্পাইলারটি কোথায় বাজে। (অনুলিপি হিসাবে অনুলিপি হিসাবে অনুলিপি নির্মাণকারী হিসাবে ট্যাগ করে একই লক্ষ্য অর্জন করা যেতে পারে।)
এলজাই

উত্তর:


2

আমি বিশ্বাস করি আপনার সঠিক পর্যবেক্ষণ আছে তবে ভুল ব্যাখ্যা!

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

ঠিক আছে, আসুন std::vectorএবং এটি নির্মাণের সময় বা ধাপে ধাপে পূরণ করে কী হবে তা নিয়ে কিছুটা খেলি lets

প্রথমত, এমন একটি ডেটা টাইপ তৈরি করা যাক যা প্রতিটি অনুলিপি তৈরি করে বা এর মতো দৃশ্যমান হয়:

template <typename DATA >
struct VisibleCopy
{
    private:
        DATA data;

    public:
        VisibleCopy( const DATA& data_ ): data{ data_ }
        {
            std::cout << "Construct " << data << std::endl;
        }

        VisibleCopy( const VisibleCopy& other ): data{ other.data }
        {
            std::cout << "Copy " << data << std::endl;
        }

        VisibleCopy( VisibleCopy&& other ) noexcept : data{ std::move(other.data) }
        {
            std::cout << "Move " << data << std::endl;
        }

        VisibleCopy& operator=( const VisibleCopy& other )
        {
            data = other.data;
            std::cout << "copy assign " << data << std::endl;
        }

        VisibleCopy& operator=( VisibleCopy&& other ) noexcept
        {
            data = std::move( other.data );
            std::cout << "move assign " << data << std::endl;
        }

        DATA Get() const { return data; }

};

এবং এখন কিছু পরীক্ষা-নিরীক্ষা শুরু করা যাক:

using T = std::vector< VisibleCopy<int> >;

T Get1() 
{   
    std::cout << "Start init" << std::endl;
    std::vector< VisibleCopy<int> > vec{ 1,2,3,4 };
    std::cout << "End init" << std::endl;
    return vec;
}   

T Get2()
{   
    std::cout << "Start init" << std::endl;
    std::vector< VisibleCopy<int> > vec(4,0);
    std::cout << "End init" << std::endl;
    return vec;
}

T Get3()
{
    std::cout << "Start init" << std::endl;
    std::vector< VisibleCopy<int> > vec;
    vec.emplace_back(1);
    vec.emplace_back(2);
    vec.emplace_back(3);
    vec.emplace_back(4);
    std::cout << "End init" << std::endl;

    return vec;
}

T Get4()
{
    std::cout << "Start init" << std::endl;
    std::vector< VisibleCopy<int> > vec;
    vec.reserve(4);
    vec.emplace_back(1);
    vec.emplace_back(2);
    vec.emplace_back(3);
    vec.emplace_back(4);
    std::cout << "End init" << std::endl;

    return vec;
}

int main()
{
    auto vec1 = Get1();
    auto vec2 = Get2();
    auto vec3 = Get3();
    auto vec4 = Get4();

    // All data as expected? Lets check:
    for ( auto& el: vec1 ) { std::cout << el.Get() << std::endl; }
    for ( auto& el: vec2 ) { std::cout << el.Get() << std::endl; }
    for ( auto& el: vec3 ) { std::cout << el.Get() << std::endl; }
    for ( auto& el: vec4 ) { std::cout << el.Get() << std::endl; }
}

আমরা কী পর্যবেক্ষণ করতে পারি:

উদাহরণ 1) আমরা একটি প্রাথমিককরণ তালিকা থেকে একটি ভেক্টর তৈরি করি এবং সম্ভবত আমরা আশা করি যে আমরা 4 বার নির্মাণ এবং 4 পদক্ষেপগুলি দেখতে পাব। তবে আমরা 4 কপি পাই! এটি কিছুটা রহস্যজনক মনে হচ্ছে, তবে কারণটি প্রাথমিকের তালিকার বাস্তবায়ন! কেবল তালিকা থেকে সরানোর অনুমতি নেই কারণ তালিকা থেকে পুনরাবৃত্তি এমন একটি const T*যা এটি থেকে উপাদান সরিয়ে নেওয়া অসম্ভব করে তোলে। এই বিষয়ের একটি বিশদ উত্তর এখানে পাওয়া যাবে: ইনিশিয়ালাইজার_লিস্ট এবং পদার্থবিদ্যার স্থানান্তর

উদাহরণ 2) এই ক্ষেত্রে, আমরা একটি প্রাথমিক নির্মাণ এবং মানটির 4 কপি পাই। এটি বিশেষ কিছু নয় এবং আমরা প্রত্যাশাও করতে পারি।

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

উদাহরণ 4) এখন আমরা স্থান সংরক্ষণ করি এবং পরে পূরণ করব। এখন আমাদের আর কোনও অনুলিপি নেই এবং কোনও পদক্ষেপ নেই!

সব ক্ষেত্রেই, আমরা ভ্যাক্টরকে একেবারেই কলারে ফেরত দিয়ে কোনও পদক্ষেপ বা অনুলিপি দেখতে পাই না! (এন) আরভিও চলছে এবং এই পদক্ষেপে আর কোনও পদক্ষেপের প্রয়োজন নেই!

আপনার প্রশ্নে ফিরে:

"সি ++ প্রফুল্ল অনুলিপি অপারেশনগুলি কীভাবে সন্ধান করবেন"

উপরের মত দেখা গেছে, আপনি ডিবাগিংয়ের উদ্দেশ্যে একটি প্রক্সি ক্লাস চালু করতে পারেন।

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

দুঃখিত যে আমি এখানে "অযাচিত" অনুলিপিগুলির সন্ধানের জন্য সাধারণ সমাধানের প্রস্তাব দিতে পারি না। এমনকি যদি আপনি কল করার জন্য আপনার কোডটি খনন করেন তবে আপনি memcpyসমস্ত কিছুই খুঁজে পাবেন না তবে এটি memcpyঅপ্টিমাইজ করা হবে এবং আপনি সরাসরি আপনার লাইব্রেরি memcpyফাংশনে কোনও কল ছাড়াই কাজটি করছেন এমন কিছু এসেম্বলারের নির্দেশাবলী দেখতে পাবেন ।

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


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

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

1

আমি জানি যে একটি অনুলিপি অপারেশন ঘটেছে কারণ আমি সংকলক এক্সপ্লোরার ব্যবহার করেছি এবং এটি ম্যাকপিকে একটি কল দেখায়।

আপনি কি কম্পাইলার এক্সপ্লোরারটিতে আপনার সম্পূর্ণ অ্যাপ্লিকেশনটি রেখেছেন এবং আপনি কী অপ্টিমাইজেশন সক্ষম করেছেন? যদি তা না হয় তবে আপনি সংকলক এক্সপ্লোরারটিতে যা দেখেছেন তা আপনার অ্যাপ্লিকেশনটির সাথে যা ঘটছে তা হতে পারে বা নাও হতে পারে।

আপনার পোস্ট করা কোডটির একটি সমস্যা হ'ল আপনি প্রথমে একটি তৈরি করেন std::vector, এবং তারপরে একটি দৃষ্টান্তে অনুলিপি করেন data। ভেক্টরের সাথে আরম্ভ করা ভাল হবে data:

data get_vector(int n)
{
  return {std::vector<int> V(n,0)};
}

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


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