স্ট্যান্ড :: রেফারেন্স_আপনার এবং সাধারণ পয়েন্টারের মধ্যে পার্থক্য?


105

কেন দরকার আছে std::reference_wrapper? এটি কোথায় ব্যবহার করা উচিত? এটি সাধারণ পয়েন্টার থেকে কীভাবে আলাদা? এর কার্য সম্পাদন কীভাবে একটি সাধারণ পয়েন্টারের সাথে তুলনা করে?


4
এটি মূলত একটি পয়েন্টার যা আপনি .পরিবর্তে ব্যবহার করেন->
এমএম

5
@ এমএম না, .আপনি যেভাবে পরামর্শ দেন সেভাবে ব্যবহার করে না (যদি না কোনও সময় অপারেটর ডট প্রস্তাব গৃহীত হয় এবং সমন্বিত হয় :))
কলম্বো

4
এই জাতীয় প্রশ্নগুলি যখন আমাকে নতুন সি ++ নিয়ে কাজ করতে হয় তখন আমাকে অসন্তুষ্ট করে তোলে।
নীল

কলম্বো অনুসরণ করতে, std :: संदर्भ_wrapper এর get()সদস্য-ফাংশন সহ বা এর অন্তর্নিহিত ধরণে অন্তর্নিহিত রূপান্তর সহ ব্যবহৃত হয় ।
সর্বোচ্চ ব্যারাক্লফ

উত্তর:


89

std::reference_wrapperটেমপ্লেটগুলির সাথে সংমিশ্রণে দরকারী। এটি কোনও পয়েন্টারটিকে এটিতে পয়েন্টার সংরক্ষণ করে পুনরায় নিয়োগের জন্য এবং অনুলিপি করার সময় তার স্বাভাবিক শব্দার্থবিজ্ঞানের অনুকরণের সময়কে আবদ্ধ করে। এটি নির্দিষ্ট গ্রন্থাগার টেমপ্লেটগুলিকে বস্তুর পরিবর্তে রেফারেন্স সঞ্চয় করার নির্দেশ দেয়।

এসটিএলে থাকা অ্যালগরিদমগুলি বিবেচনা করুন যা ফান্ট্যাক্টরদের অনুলিপি করে: আপনি কেবল ফান্টারের পরিবর্তে ফান্টারের সাথে উল্লেখ করে একটি রেফারেন্স ਰੈਪਰটি পাস করে সেই অনুলিপিটি এড়াতে পারবেন:

unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state

এটি কাজ করে কারণ ...

  • reference_wrapperএর ওভারলোডoperator() যাতে তারা ফাংশন অবজেক্টগুলির মতো ঠিক তেমন কল করা যায়:

    std::ref(myEngine)() // Valid expression, modifies myEngines state
    
  • … (আনইন) সাধারণ রেফারেন্সগুলির মতো, অনুলিপি করা (এবং কার্যবিবরণ করা) reference_wrappersকেবলমাত্র পয়েন্টিকে নির্ধারিত করে।

    int i, j;
    auto r = std::ref(i); // r refers to i
    r = std::ref(j); // Okay; r refers to j
    r = std::cref(j); // Error: Cannot bind reference_wrapper<int> to <const int>
    

একটি রেফারেন্স র‌্যাপার অনুলিপি করা কার্যত পয়েন্টার অনুলিপি করার সমতুল্য, এটি যতটা সস্তা cheap সমস্ত ফাংশন এটি ব্যবহারের অন্তর্নিহিত কলগুলি (উদাহরণস্বরূপ যা operator()তারা এক-লাইনার হিসাবে ঠিক তেমনভাবে ইনলাইন করা উচিত)।

reference_wrapperগুলি এর মাধ্যমে তৈরি হয় std::refএবংstd::cref :

int i;
auto r = std::ref(i); // r is of type std::reference_wrapper<int>
auto r2 = std::cref(i); // r is of type std::reference_wrapper<const int>

টেমপ্লেট আর্গুমেন্ট উল্লেখ করা বস্তুর প্রকার এবং সিভি-যোগ্যতা নির্দিষ্ট করে; r2এটিকে বোঝায় const intএবং কেবলমাত্র একটি রেফারেন্স দেবে const int। এর constমধ্যে ফ্যান্টরস সহ মোড়ক রেফারেন্সের কলগুলি কেবল constসদস্য ফাংশনকে কল করবে operator()

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

লাইব্রেরি ইন্টারঅ্যাকশন

পূর্বে উল্লিখিত হিসাবে, যে make_tupleকোনও tupleদ্বারা সম্পর্কিত যুক্তিটি পাস করে ফলাফলের মধ্যে একটি রেফারেন্স সঞ্চয় করার নির্দেশ দিতে পারে reference_wrapper:

int i;
auto t1 = std::make_tuple(i); // Copies i. Type of t1 is tuple<int>
auto t2 = std::make_tuple(std::ref(i)); // Saves a reference to i.
                                        // Type of t2 is tuple<int&>

নোট করুন যে এটি থেকে কিছুটা পৃথক forward_as_tuple: এখানে, আর্গুমেন্ট হিসাবে মূল্যগুলি অনুমোদিত নয়।

std::bindএকই আচরণ দেখায়: এটি যুক্তির অনুলিপি করবে না তবে এটি যদি একটি রেফারেন্স সঞ্চয় করে reference_wrapper। কার্যকর যদি সেই যুক্তিটি (বা ফান্টেক্টর!) অনুলিপি করা না প্রয়োজন তবে- bindফান্টর ব্যবহার করার সময় স্কোপে থাকে ।

সাধারণ পয়েন্টার থেকে পার্থক্য

  • সিনট্যাক্টিকাল ইন্ডায়ারেশনের কোনও অতিরিক্ত স্তর নেই। পয়েন্টারগুলিকে তারা যে বস্তুটি উল্লেখ করে তার লভ্যালু অর্জনের জন্য উপযুক্ত হতে হবে; reference_wrapperএর একটি অন্তর্নিহিত রূপান্তর অপারেটর রয়েছে এবং তাদের মোড়ানো বস্তুর মতো বলা যেতে পারে।

    int i;
    int& ref = std::ref(i); // Okay
    
  • reference_wrappers, পয়েন্টারগুলির বিপরীতে, নাল অবস্থা নেই। সেগুলি রেফারেন্স বা অন্য কোনওreference_wrapper দিয়ে শুরু করতে হবে ।

    std::reference_wrapper<int> r; // Invalid
    
  • একটি সাদৃশ্য হ'ল অগভীর অনুলিপি শব্দার্থক: পয়েন্টার এবং reference_wrapperগুলি পুনরায় নিয়োগ দেওয়া যেতে পারে।


কি std::make_tuple(std::ref(i));শ্রেয় std::make_tuple(&i);কিছু উপায়?
লরিয়ানাস লাজাউস্কাস

7
@ লৌরিনাস লাজাউস্কাস এটির চেয়ে আলাদা। আপনি যেটি পরে দেখিয়েছেন এটি কোনও পয়েন্টার সংরক্ষণ করে i, এটির কোনও উল্লেখ নেই।
কলম্বো

এইচএম ... আমার ধারণা আমি এখনও এই দুটি আলাদা করতে পারি না পাশাপাশি আমিও চাই ... ভাল, আপনাকে ধন্যবাদ
লরিয়ানাস লাজাউস্কাস

@ কলম্বো যদি নাল অবস্থা না করে রেফারেন্স র‌্যাপের একটি অ্যারে কীভাবে সম্ভব? অ্যারেগুলি সাধারণত সমস্ত উপাদান নਾਲ স্টেটে সেট করা শুরু হয় না?
অ্যানাটলিগ

4
@ অ্যানাটলিগ আপনাকে এই অ্যারেটি শুরু করতে বাধা দেয় কি?
কলম্বো

27

কমপক্ষে, দুটি উদ্দেশ্যমূলক উদ্দেশ্য রয়েছে std::reference_wrapper<T>:

  1. এটি ফাংশন টেম্পলেটগুলির মান প্যারামিটার হিসাবে পাস হওয়া অবজেক্টগুলিকে রেফারেন্স সিমানটিকগুলি দেওয়া হয়। উদাহরণস্বরূপ, আপনার কাছে একটি বৃহত ফাংশন অবজেক্ট থাকতে পারে std::for_each()যা আপনি পাস করতে চান যা তার ফাংশন অবজেক্ট প্যারামিটারকে মান দ্বারা নেয়। অবজেক্টটি অনুলিপি করা এড়াতে, আপনি ব্যবহার করতে পারেন

    std::for_each(begin, end, std::ref(fun));
    

    std::reference_wrapper<T>একটি std::bind()অভিব্যক্তি হিসাবে আর্গুমেন্ট পাস মান হিসাবে বরং রেফারেন্স দ্বারা যুক্তি বাঁধা যথেষ্ট সাধারণ।

  2. সংশ্লিষ্ট টিউপল উপাদানটির std::reference_wrapper<T>সাথে একটি ব্যবহার করার সময় একটি পরিবর্তে std::make_tuple()পরিণত হয় :T&T

    T object;
    f(std::make_tuple(1, std::ref(object)));
    

আপনি কি দয়া করে প্রথম কেসের জন্য একটি কোড উদাহরণ দিতে পারেন?
ব্যবহারকারী1708860

4
@ ইউজার ১70০৮6060০: আপনার দেওয়া মানে বাদে অন্য মানে ...?
ডায়েটমার কাহল

আমার অর্থ আসল কোড যা এসটিডি :: রেফ (মজাদার) এর সাথে যায় কারণ আমি কীভাবে ব্যবহার করা হয় তা বুঝতে পারি না (মজা না করা
অবধি

4
@ ব্যবহারকারী1708860: হ্যাঁ, বেশিরভাগ সম্ভবত funকোনও ফাংশন অবজেক্ট (অর্থাত্ কোনও ফাংশন কল অপারেটর সহ কোনও শ্রেণীর কোনও বস্তু) এবং কোনও ফাংশন নয়: যদি funকোনও আসল ফাংশন হয়ে std::ref(fun)থাকে তবে কোনও উদ্দেশ্য নেই এবং কোডটি সম্ভাব্যভাবে ধীর করে দিন।
ডায়েটমার কাহল

23

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

vector<int*> a;                    // the int values might or might not be owned
vector<unique_ptr<int>> b;         // the int values are definitely owned
vector<reference_wrapper<int>> c;  // the int values are definitely not owned

4
এটি প্রাক-সি ++ ১১ কোড না থাকলে প্রথম উদাহরণটিতে alচ্ছিক, অজানা মানগুলি বোঝানো উচিত, উদাহরণস্বরূপ সূচকের উপর ভিত্তি করে ক্যাশে দেখার জন্য। ভাল লাগবে যদি স্টাডেন্ট আমাদের নন-নাল, মালিকানাধীন মান (অনন্য এবং ভাগ করা রূপগুলি) উপস্থাপনের জন্য কিছু মানদণ্ড সরবরাহ করে
Bwmat

এটি সম্ভবত সি ++ 11 তে ততটা গুরুত্বপূর্ণ নয়, যেখানে খালি পয়েন্টার যেভাবেই প্রায় সবসময় ধার করা মান হবে।
Elling

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

20

আপনি এটিকে রেফারেন্সের চারপাশে সুবিধাযুক্ত মোড়ক হিসাবে ভাবতে পারেন যাতে আপনি সেগুলি পাত্রে ব্যবহার করতে পারেন।

std::vector<std::reference_wrapper<T>> vec; // OK - does what you want
std::vector<T&> vec2; // Nope! Will not compile

এটি মূলত একটি CopyAssignableসংস্করণ T&। আপনি যে কোনও সময় রেফারেন্স চান, তবে এটি নির্ধারিত, ব্যবহার std::reference_wrapper<T>বা তার সহায়ক ফাংশন হতে হবে std::ref()। অথবা পয়েন্টার ব্যবহার করুন।


অন্যান্য quirks sizeof:

sizeof(std::reference_wrapper<T>) == sizeof(T*) // so 8 on a 64-bit box
sizeof(T&) == sizeof(T) // so, e.g., sizeof(vector<int>&) == 24

এবং তুলনা:

int i = 42;
assert(std::ref(i) == std::ref(i)); // ok

std::string s = "hello";
assert(std::ref(s) == std::ref(s)); // compile error

4
@ লৌরিনাস লাজাউস্কাস যিনি সরাসরি মোড়কে থাকা ফাংশন অবজেক্টগুলিকে সরাসরি কল করতে পারেন। এটি আমার উত্তরেও ব্যাখ্যা করা হয়েছে।
কলম্বো

4
যেহেতু রেফারেন্স বাস্তবায়ন কেবলমাত্র অভ্যন্তরের একটি পয়েন্টার তাই আমি বুঝতে পারি না কেন মোড়করা কোনও দিকনির্দেশনা বা পারফরম্যান্স জরিমানা যুক্ত করে
রিগা

4
রিলিজ কোডের কথা বলতে গেলে এটি কোনও সাধারণ রেফারেন্সের চেয়ে বেশি ইন্ডিয়ারেশন হওয়া উচিত নয়
রিগা

4
আমি সংকলকটি তুচ্ছ reference_wrapperকোডটি ইনলাইন করার প্রত্যাশা করব , এটি কোডের মতো যা একটি পয়েন্টার বা রেফারেন্স ব্যবহার করে ident
ডেভিড স্টোন

4
@ লৌরিনাস লাজাউস্কাস: std::reference_wrapperগ্যারান্টি রয়েছে যে বিষয়টি কখনই বাতিল হবে না। একটি শ্রেণীর সদস্য বিবেচনা করুন std::vector<T *>। এই বস্তুটি কখনও nullptrভেক্টরে কোনও সঞ্চয় করতে পারে কিনা তা দেখতে আপনাকে সমস্ত শ্রেণি কোড পরীক্ষা করে দেখতে হবে , অন্যদিকে std::reference_wrapper<T>, আপনাকে বৈধ অবজেক্টের নিশ্চয়তা দেওয়া হচ্ছে।
ডেভিড স্টোন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.