সি ++ এ রেফারেন্স দ্বারা একটি পয়েন্টার পাস করার কারণ?


101

আপনি কোন পরিস্থিতিতে সি ++ এ এই প্রকৃতির কোড ব্যবহার করতে চান?

void foo(type *&in) {...}

void fii() {
  type *choochoo;
  ...
  foo(choochoo);
}

আপনার যদি কোনও পয়েন্টার ফিরিয়ে দিতে হয়
ভালভাবে

6
কেন আপনি ব্যাখ্যা করতে পারেন? এই প্রশংসা খুব সহায়ক নয়। আমার প্রশ্ন বেশ বৈধ। এটি বর্তমানে প্রোডাকশন কোডে ব্যবহৃত হচ্ছে। আমি শুধু পুরো কারণ বুঝতে পারি না কেন।
ম্যাথু হোগান

4
ডেভিড এটি খুব সুন্দরভাবে যোগ করে দেয়। পয়েন্টারটি নিজেই সংশোধন করা হচ্ছে।
ক্রিস

4
আমি যদি ফাংশনে "নতুন" অপারেটরটিকে কল করতে পারি তবে আমি এইভাবে পাস করি।
এনডিডিথোস

উত্তর:


148

আপনি যদি পয়েন্টারটি নির্দেশ করছেন সেই বস্তুর পরিবর্তে পয়েন্টারটি পরিবর্তনের প্রয়োজন হয় তবে আপনি রেফারেন্স দিয়ে একটি পয়েন্টারটি পাস করতে চান।

এটি কেন ডাবল পয়েন্টার ব্যবহার করা হয় তার অনুরূপ; পয়েন্টার ব্যবহারের চেয়ে রেফারেন্স ব্যবহার করা কিছুটা নিরাপদ sa


14
পাস-বাই-রেফারেন্স শব্দার্থবিজ্ঞানের জন্য ইন্ডিরেশন এর এক কম স্তরের বাদে কোনও পয়েন্টারের পয়েন্টারের অনুরূপ?

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

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

4
@ বারবারকওয়ার্ক শিওর বলুন আপনার একটি গতিশীল অ্যারের সাধারণ প্রয়োগ রয়েছে have স্বাভাবিকভাবেই আপনি []অপারেটরটি ওভারলোড করবেন । এর জন্য একটি সম্ভাব্য (এবং প্রকৃতপক্ষে প্রাকৃতিক) স্বাক্ষর হবে const T &operator[](size_t index) const। তবে আপনিও থাকতে পারতেন T &operator[](size_t index)। আপনি একই সাথে উভয় থাকতে পারে। পরেরটি আপনাকে পছন্দ মতো কাজ করতে দেয় myArray[jj] = 42। একই সময়ে, আপনি আপনার ডেটাতে একটি পয়েন্টার সরবরাহ করছেন না, তাই কলার স্মৃতিতে গোলযোগ করতে পারে না (যেমন এটি দুর্ঘটনাক্রমে মুছুন)।

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

67

সি ++ প্রোগ্রামারদের 50% তাদের মুদ্রক মুছার পরে পয়েন্টারগুলি বাতিল করতে চান:

template<typename T>    
void moronic_delete(T*& p)
{
    delete p;
    p = nullptr;
}

উল্লেখ ছাড়াই আপনি কেবল পয়েন্টারের স্থানীয় কপি পরিবর্তন করবেন, কলকারীকে প্রভাবিত করবেন না।


19
নামটি আমার পছন্দ; )
4pie0

4
আমি উত্তরটি খুঁজে বের করার জন্য বোকা বোকা বাণিজ্য করব: কেন তাকে মরোনিক মোছা বলা হয়? আমি কী মিস করছি?
সামারন

4
@ সাম্মারন আপনি যদি ইতিহাসের দিকে তাকান তবে ফাংশন টেম্পলেটটি বলা হত paranoid_delete, তবে কুকুরছানা এটির নামকরণ করে moronic_delete। তিনি সম্ভবত অন্যান্য 50% এর অন্তর্ভুক্ত) যাইহোক, সংক্ষিপ্ত উত্তরটি হ'ল সেটিংসটি পরে নালার দিকে নির্দেশ করে deleteপ্রায় কখনও কার্যকর হয় না (কারণ তাদের যেভাবেই সুযোগের বাইরে চলে যাওয়া উচিত) এবং প্রায়শই "বিনামূল্যে পরে" বাগগুলি সনাক্তকরণকে বাধা দেয়।
ফ্রেডওভারফ্লো

@ ফ্রেডওভারফ্লো আমি আপনার প্রতিক্রিয়াটি বুঝতে পারি তবে @ পপি মনে হয় deleteসাধারণভাবে বোকা। কুকুরছানা, আমি কিছু গুগল করেছিলাম, কেন মুছুন সম্পূর্ণরূপে অকেজো বলে আমি দেখতে পাচ্ছি না (সম্ভবত আমি খুব ভয়ঙ্কর গুগলারের;))। আপনি কি আরও কিছু ব্যাখ্যা করতে পারেন বা একটি লিঙ্ক সরবরাহ করতে পারেন?
সামারমন

@ সাম্মারন, সি ++ এর এখন "স্মার্ট পয়েন্টার" রয়েছে যা নিয়মিত পয়েন্টারগুলি সজ্জিত করে এবং সুযোগের বাইরে চলে গেলে স্বয়ংক্রিয়ভাবে আপনার জন্য "মুছুন" কল করে। স্মার্ট পয়েন্টারগুলি সি-স্টাইলের বোবা পয়েন্টারগুলির চেয়ে বেশি পছন্দ করা হয় কারণ তারা এই সমস্যাটিকে পুরোপুরি দূর করে।
tjwrona1992

15

ডেভিডের উত্তরটি সঠিক, তবে এটি যদি এখনও কিছুটা বিমূর্ত হয়, তবে এখানে দুটি উদাহরণ রয়েছে:

  1. মেমরির সমস্যাগুলি আগে পেতে আপনি সমস্ত মুক্ত পয়েন্টার শূন্য করতে চাইতে পারেন। সি-স্টাইল আপনি করতেন:

    void freeAndZero(void** ptr)
    {
        free(*ptr);
        *ptr = 0;
    }
    
    void* ptr = malloc(...);
    
    ...
    
    freeAndZero(&ptr);
    

    সি ++ এ একই কাজ করতে, আপনি এটি করতে পারেন:

    template<class T> void freeAndZero(T* &ptr)
    {
        delete ptr;
        ptr = 0;
    }
    
    int* ptr = new int;
    
    ...
    
    freeAndZero(ptr);
    
  2. লিঙ্কযুক্ত-তালিকাগুলি নিয়ে কাজ করার সময় - প্রায়শই কেবল পরবর্তী নোডের পয়েন্টার হিসাবে উপস্থাপন করা হয়:

    struct Node
    {
        value_t value;
        Node* next;
    };
    

    এই ক্ষেত্রে, আপনি খালি তালিকায় sertোকানোর সময় আপনাকে অবশ্যই আগত পয়েন্টারটি অবশ্যই পরিবর্তন করতে হবে কারণ ফলাফলটি NULLআর পয়েন্টার নয়। এটি এমন একটি ক্ষেত্রে যেখানে আপনি কোনও ফাংশন থেকে বাহ্যিক পয়েন্টারটি সংশোধন করেন, সুতরাং এটির স্বাক্ষরে পয়েন্টারের একটি রেফারেন্স থাকবে:

    void insert(Node* &list)
    {
        ...
        if(!list) list = new Node(...);
        ...
    }
    

এই প্রশ্নের একটি উদাহরণ আছে ।


8

পাশ করা পয়েন্টারের কাছে মেমরি বরাদ্দ করতে ফাংশন সরবরাহ করতে এবং এর আকারটি ফিরিয়ে দিতে আমাকে এই জাতীয় কোড ব্যবহার করতে হয়েছিল কারণ আমার সংস্থাটি এসটিএল ব্যবহার করে আমার "অবজেক্ট" করেছে

 int iSizeOfArray(int* &piArray) {
    piArray = new int[iNumberOfElements];
    ...
    return iNumberOfElements;
 }

এটি দুর্দান্ত নয়, তবে পয়েন্টারটি অবশ্যই রেফারেন্স দিয়ে পাস করতে হবে (বা ডাবল পয়েন্টার ব্যবহার করুন)। যদি তা না হয় তবে মেমোরিটিকে পয়েন্টারের স্থানীয় অনুলিপিতে বরাদ্দ করা হয় যদি এটি মান দ্বারা পাস করা হয় যার ফলে মেমরি ফাঁস হয়।


2

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

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


ডাউনটা কেন? আমি যা লিখেছি তাতে কিছু ভুল আছে? বোঝাতে কি যত্ন? : পি
বারবারাওয়ার্ক

0

আপনি যখন এটির প্রয়োজন হতে পারে তখন অন্য একটি পরিস্থিতি হ'ল যদি আপনার কাছে পয়েন্টার সংগ্রহ থাকে এবং স্টিল অ্যালগরিদম ব্যবহার করে সেগুলি পরিবর্তন করতে চান। সি ++ 98 এ for_each এর উদাহরণ।

struct Storage {
  typedef std::list<Object*> ObjectList;
  ObjectList objects;

  void change() {
    typedef void (*ChangeFunctionType)(Object*&);
    std::for_each<ObjectList::iterator, ChangeFunctionType>
                 (objects.begin(), objects.end(), &Storage::changeObject);
  }

  static void changeObject(Object*& item) {
    delete item;
    item = 0;
    if (someCondition) item = new Object();
  } 

};

অন্যথায়, যদি আপনি চেঞ্জঅবজেক্ট (অবজেক্ট * আইটেম) স্বাক্ষর ব্যবহার করেন তবে আপনার পয়েন্টারের অনুলিপি রয়েছে, মূলটি নয়।


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