পয়েন্টার ভেরিয়েবল এবং সি ++ এ একটি রেফারেন্স ভেরিয়েবলের মধ্যে পার্থক্য কী?


3260

আমি জানি রেফারেন্সগুলি সিনট্যাকটিক চিনি, তাই কোড পড়া এবং লেখা সহজ।

তবে পার্থক্য কী?


100
আমি মনে করি পয়েন্ট 2 হওয়া উচিত "একটি পয়েন্টারকে NULL হওয়ার অনুমতি দেওয়া হয় তবে একটি রেফারেন্স হয় না Only শুধুমাত্র ত্রুটিযুক্ত কোডটি একটি NULL রেফারেন্স তৈরি করতে পারে এবং এর আচরণটি অপরিজ্ঞাত।"
মার্ক রান্সম

19
পয়েন্টারগুলি কেবলমাত্র অন্য ধরণের অবজেক্ট এবং সি ++ এর যে কোনও বস্তুর মতো এগুলিও চলক হতে পারে। অন্যদিকে উল্লেখগুলি কখনই বস্তু নয়, কেবল পরিবর্তনশীল।
কেরেক এসবি

19
এটি সতর্কতা ছাড়াই সংকলন করে: int &x = *(int*)0;সিসিটিতে। রেফারেন্সটি আসলে নুলকে নির্দেশ করতে পারে।
ক্যালমারিয়াস

20
রেফারেন্সটি একটি পরিবর্তনশীল ওরফে
খালেদ.কে

20
আমি পছন্দ করি যে প্রথম বাক্যটি কীভাবে সম্পূর্ণ ভুল। রেফারেন্সগুলির নিজস্ব শব্দার্থবিজ্ঞান রয়েছে।
অরবিট

উত্তর:


1704
  1. একটি পয়েন্টার পুনরায় বরাদ্দ করা যেতে পারে:

    int x = 5;
    int y = 6;
    int *p;
    p = &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);
    

    একটি রেফারেন্স পারে না, এবং প্রারম্ভিক সময়ে নির্ধারিত হতে হবে:

    int x = 5;
    int y = 6;
    int &r = x;
    
  2. একটি পয়েন্টারের স্ট্যাকের নিজস্ব মেমরি ঠিকানা এবং আকার থাকে (x86 এ 4 বাইট), যেখানে একটি রেফারেন্স একই মেমরি ঠিকানা ভাগ করে (মূল ভেরিয়েবল সহ) তবে স্ট্যাকের উপরে কিছু জায়গা নেয়। যেহেতু একটি রেফারেন্সের মূল ভেরিয়েবলের একই ঠিকানা থাকে, তাই একই ভেরিয়েবলের অন্য নাম হিসাবে কোনও রেফারেন্সটি ভাবা নিরাপদ। দ্রষ্টব্য: একটি পয়েন্টার পয়েন্ট কী স্ট্যাক বা গাদা হতে পারে। একটি রেফারেন্স। এই বিবৃতিতে আমার দাবিটি নয় যে কোনও পয়েন্টার অবশ্যই স্ট্যাকের দিকে নির্দেশ করবে। একটি পয়েন্টার কেবল একটি পরিবর্তনশীল যা একটি স্মৃতি ঠিকানা রাখে। এই ভেরিয়েবলটি স্ট্যাকের মধ্যে রয়েছে। যেহেতু একটি রেফারেন্সের স্ট্যাকের নিজস্ব স্থান রয়েছে এবং যেহেতু ঠিকানাটি তার উল্লেখযোগ্য পরিবর্তকের মত একই। আরো স্ট্যাক গাদা বনাম। এটি সূচিত করে যে এখানে একটি রেফারেন্সের আসল ঠিকানা রয়েছে যা সংকলক আপনাকে বলবে না।

    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);
    
  3. আপনার পয়েন্টারগুলিতে পয়েন্টারগুলিতে পয়েন্টারগুলিতে অতিরিক্ত মাত্রার ইন্ডিয়ারেশন প্রস্তাব করতে পারে। যদিও রেফারেন্সগুলি কেবলমাত্র এক স্তরের ইন্ডিয়ারেশনের প্রস্তাব দেয়।

    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    pp = &q;//*pp = q
    **pp = 4;
    assert(y == 4);
    assert(x == 0);
    
  4. একটি পয়েন্টার nullptrসরাসরি বরাদ্দ করা যেতে পারে , যেখানে রেফারেন্স পারে না। যদি আপনি যথেষ্ট চেষ্টা করেন এবং আপনি কীভাবে জানেন তবে আপনি কোনও রেফারেন্সের ঠিকানাটি তৈরি করতে পারেন nullptr। তেমনি, আপনি যদি যথেষ্ট চেষ্টা করেন তবে আপনার পয়েন্টারের একটি রেফারেন্স থাকতে পারে এবং তারপরে সেই উল্লেখটি থাকতে পারে nullptr

    int *p = nullptr;
    int &r = nullptr; <--- compiling error
    int &r = *p;  <--- likely no compiling error, especially if the nullptr is hidden behind a function call, yet it refers to a non-existent int at address 0
    
  5. পয়েন্টারগুলি একটি অ্যারের উপরে পুনরাবৃত্তি করতে পারে; আপনি ++পরবর্তী আইটেমটিতে যেতে পারেন যা একটি পয়েন্টারটি নির্দেশ করছে এবং + 45 তম উপাদানটিতে যেতে পারে। পয়েন্টারটি পয়েন্টারটি যে আকারের তা কোন বিষয় নয়।

  6. কোনও পয়েন্টারটিকে *মেমোরির অবস্থান নির্দেশ করার জন্য এটির সাথে ডিফারেন্স করা দরকার, যেখানে সরাসরি একটি রেফারেন্স ব্যবহার করা যেতে পারে। শ্রেণি / কাঠামোর একটি পয়েন্টার ->এর সদস্যদের অ্যাক্সেস করতে ব্যবহার করে যেখানে একটি রেফারেন্স ব্যবহার করে .

  7. রেফারেন্সগুলি একটি অ্যারেতে স্টাফ করা যায় না, তবে পয়েন্টারগুলি (ব্যবহারকারী @ লিটিব দ্বারা উল্লেখ করা) হতে পারে

  8. কনস্টের রেফারেন্সগুলি অস্থায়ীভাবে আবদ্ধ হতে পারে। পয়েন্টারগুলি (কোনও দিকনির্দেশ ছাড়াই নয়):

    const int &x = int(12); //legal C++
    int *y = &int(12); //illegal to dereference a temporary.
    

    এটি const&আর্গুমেন্ট তালিকাগুলিতে ব্যবহারের জন্য আরও সুরক্ষিত করে।


23
... তবে এনআরএলকে ডিফারেন্স করা অপরিজ্ঞাত। উদাহরণস্বরূপ, আপনি পরীক্ষা করতে পারবেন না যদি কোনও রেফারেন্স নুল হয় (যেমন, & রেফ == নুল)।
প্যাট নটজ

69
সংখ্যা 2 হয় না সত্য। একটি রেফারেন্স কেবল "একই ভেরিয়েবলের আর একটি নাম" নয়। রেফারেন্সগুলি ফাংশনগুলিতে পাস করা যেতে পারে, ক্লাসে সংরক্ষণ করা ইত্যাদি পয়েন্টারের সাথে খুব অনুরূপ পদ্ধতিতে। তারা যে ভেরিয়েবলগুলি নির্দেশ করে সেগুলি থেকে তারা স্বাধীনভাবে বিদ্যমান exist
ডেরেক পার্ক

31
ব্রায়ান, স্ট্যাকটি প্রাসঙ্গিক নয়। রেফারেন্স এবং পয়েন্টারগুলিকে স্ট্যাকের স্থান নিতে হবে না। তারা উভয় গাদা উপর বরাদ্দ করা যেতে পারে।
ডেরেক পার্ক 4

22
ব্রায়ান, একটি পরিবর্তনশীল (এই ক্ষেত্রে কোনও পয়েন্টার বা রেফারেন্স) এর জন্য স্থান প্রয়োজন তার অর্থ এই নয় যে এটি স্ট্যাকের জন্য স্থান প্রয়োজন। পয়েন্টার এবং রেফারেন্সগুলি কেবল স্তূপের দিকে নির্দেশ করে না, সেগুলি আসলে গাদাতে বরাদ্দ থাকতে পারে ।
ডেরেক পার্ক

38
আরেকটি গুরুত্বপূর্ণ পার্থক্য: রেফারেন্সগুলি একটি অ্যারেতে স্টাফ করা যায় না
জোহানেস স্কাউব - লিটব

381

একটি সি ++ রেফারেন্স কী ( সি প্রোগ্রামারদের জন্য )

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

সমস্ত রেফারেন্স অবশ্যই নন-নাল মান দিয়ে শুরু করতে হবে বা সংকলন ব্যর্থ হবে। কোনও রেফারেন্সের ঠিকানা পাওয়া সম্ভব নয় - ঠিকানার পরিবর্তে অ্যাড্রেস অপারেটর রেফারেন্সযুক্ত মানটির ঠিকানা ফিরিয়ে দেবে - বা রেফারেন্সগুলিতে পাটিগণিত করাও সম্ভব নয়।

সি প্রোগ্রামাররা সি ++ রেফারেন্সগুলি অপছন্দ করতে পারে কারণ ইন্ডিয়ারেশন যখন ঘটে তখন এটি আর স্পষ্ট হবে না বা যদি কোনও আর্গুমেন্ট মান দ্বারা বা বিন্দু দ্বারা ফাংশন স্বাক্ষরগুলি না দেখিয়ে পাস হয়ে যায়।

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

সি ++ এফএকিউ থেকে নিম্নলিখিত বিবৃতিটি বিবেচনা করুন :

যদিও অন্তর্নিহিত সমাবেশ ভাষায় কোনও ঠিকানা ব্যবহার করে একটি রেফারেন্স প্রায়শই প্রয়োগ করা হয় তবে দয়া করে কোনও বিষয়টিকে কোনও মজাদার চেহারা হিসাবে দেখবেন না । একটি রেফারেন্স হ'ল অবজেক্ট। এটি কোনও বস্তুর প্রতি নির্দেশক নয়, না কোনও বস্তুর অনুলিপিও। এটা তোলে হয় অবজেক্ট।

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

আমি কেন সি ++ রেফারেন্সকে দরকারী মনে করি

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

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


17
@ ক্রিস: না, আপনি রেফারেন্স সহ একটি স্বয়ংক্রিয় ভেরিয়েবল ফেরত দিয়ে ঝুঁকির রেফারেন্সও পেতে পারেন।
বেন ভয়েগট

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

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

7
তথ্যসূত্রগুলি এক ধরণের পয়েন্টার নয়। বিদ্যমান বস্তুর জন্য এগুলি একটি নতুন নাম।
ক্যাটফাইভ

18
@ ক্যাটফাইভ: আপনি যদি ভাষা শব্দার্থবিজ্ঞানের ভিত্তিতে যান তবে সত্য যদি আপনি বাস্তবায়নের দিকে লক্ষ্য করেন তবে সত্য নয়; সি ++ হ'ল এক আরও 'জাদুকরী' ভাষা যা সি, এবং আপনি যদি যাদুটিকে রেফারেন্স থেকে সরিয়ে দেন তবে আপনি একটি পয়েন্টার দিয়ে শেষ করবেন
ক্রিস্টোফ

190

আপনি যদি সত্যই পেডেন্টিক হতে চান তবে একটি জিনিস যা আপনি একটি পয়েন্টার দিয়ে করতে পারবেন না এমন একটি রেফারেন্স সহ করতে পারেন: একটি অস্থায়ী বস্তুর আজীবন প্রসারিত করুন। সি ++ এ আপনি যদি কোনও অস্থায়ী অবজেক্টের জন্য একটি দৃ const় রেফারেন্স বেঁধে রাখেন তবে object বস্তুর আজীবন রেফারেন্সের আজীবন হয়ে যায়।

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

এই উদাহরণে s3_copy অস্থায়ী বস্তুটি অনুলিপি করে যা সংঘবদ্ধতার ফলাফল। যেখানে মূলত s3_references অস্থায়ী বস্তুতে পরিণত হয়। এটি সত্যিই একটি অস্থায়ী অবজেক্টের একটি রেফারেন্স যার রেফারেন্সটির এখনকার জীবনকাল।

আপনি যদি constএটির চেষ্টা না করে এটি সংকলন করতে ব্যর্থ হওয়া উচিত। আপনি কোনও অস্থায়ী অবজেক্টের জন্য অবিচ্ছিন্ন রেফারেন্সকে বেঁধে রাখতে পারবেন না, আপনি এই বিষয়ে তার ঠিকানা নিতে পারবেন না।


5
তবে এর জন্য ইউস কেস কী?
আহমদ মোশতাক

20
ঠিক আছে, s3_copy একটি অস্থায়ী তৈরি করবে এবং তারপরে এটি অনুলিপি করে s3_copy এ তৈরি করবে যেখানে s3_references সরাসরি অস্থায়ী ব্যবহার করে। তারপরে সত্যিকারের পেডেন্টিক হওয়ার জন্য আপনাকে রিটার্ন মান অপ্টিমাইজেশনের দিকে নজর দেওয়া দরকার যার মাধ্যমে সংকলকটিকে প্রথম ক্ষেত্রে অনুলিপি নির্মাণের অনুমতি দেওয়া হয়েছিল।
ম্যাট প্রাইস

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

9
সি ++ 11 এর জন্য আপডেট করুন: শেষ বাক্য পড়া উচিত "আপনি করতে পারেন না বেঁধে একটি অস্থায়ী করার জন্য একটি অ const lvalue রেফারেন্স" কারণ আপনার পারেন একটি অ-const বাঁধে rvalue একটি অস্থায়ী রেফারেন্স, এবং এটি একই জীবদ্দশায়-ব্যাপ্ত আচরণ আছে।
Oktalist

4
@ আহমাদ মুশতাক: এর মূল ব্যবহারটি ক্লাস থেকে নেওয়া । যদি কোনও উত্তরাধিকার জড়িত না থাকে তবে আপনি ভাল মানের শব্দার্থক ব্যবহার করতে পারেন যা আরভিও / সরানো নির্মাণের কারণে সস্তা বা বিনামূল্যে হবে। তবে আপনার যদি Animal x = fast ? getHare() : getTortoise()পরে থাকে তবে xক্লাসিক স্লাইসিং সমস্যার মুখোমুখি হবেন, যখন Animal& x = ...সঠিকভাবে কাজ করবে।
আর্থার টাক্কা

127

সিনট্যাকটিক চিনি ছাড়াও, একটি রেফারেন্স একটি constপয়েন্টার ( কোনওটির দিকে নির্দেশক নয়const )। আপনি যখন রেফারেন্স ভেরিয়েবল ঘোষণা করবেন তখন আপনাকে অবশ্যই এটি স্থাপন করতে হবে এবং আপনি পরে এটিকে পরিবর্তন করতে পারবেন না।

আপডেট: এখন যেহেতু আমি এটি সম্পর্কে আরও কিছু চিন্তা করি, সেখানে একটি গুরুত্বপূর্ণ পার্থক্য রয়েছে।

কোনও কনস্ট পয়েন্টারের লক্ষ্য তার ঠিকানা গ্রহণ এবং কনস্ট কাস্ট ব্যবহার করে প্রতিস্থাপন করা যেতে পারে।

কোনও রেফারেন্সের টার্গেট কোনওভাবেই ইউবির সংক্ষেপে প্রতিস্থাপন করা যাবে না।

এটি কম্পাইলারকে একটি রেফারেন্সে আরও অনুকূলকরণের অনুমতি দেওয়া উচিত do


8
আমি মনে করি এটি এখন পর্যন্ত সেরা উত্তর। অন্যরা রেফারেন্স এবং পয়েন্টারগুলি সম্পর্কে কথা বলে যে তারা ভিন্ন ভিন্ন জন্তু এবং তারপরে তারা আচরণে কীভাবে আলাদা হয় তা নির্ধারণ করে। এটি কোনও সহজ ইমো করে না। আমি রেফারেন্সগুলিকে সর্বদা T* constআলাদা সিনট্যাকটিক চিনির সাথে বুঝতে পেরেছি (যা আপনার কোড থেকে * এবং প্রচুর পরিমাণে মুছে ফেলার জন্য ঘটে)।
কার্লো উড

2
"কোনও কনস্ট পয়েন্টারের লক্ষ্য তার ঠিকানা নিয়ে এবং কনস্ট কাস্ট ব্যবহার করে প্রতিস্থাপন করা যেতে পারে।" এটি করা অপরিবর্তিত আচরণ। বিশদ জানতে stackoverflow.com/questions/25209838/… দেখুন ।
Dgnuff

1
কোনও রেফারেন্সের রেফারেন্স বা কনস্ট পয়েন্টার (বা কোনও কনস্ট্যান্ট স্কেলার) এর মান পরিবর্তন করার চেষ্টা করা সমতা অবৈধ is আপনি যা করতে পারেন: অন্তর্নিহিত রূপান্তর দ্বারা যুক্ত করা হয়েছে এমন একটি কনস্টের যোগ্যতা অপসারণ: int i; int const *pci = &i; /* implicit conv to const int* */ int *pi = const_cast<int*>(pci);ঠিক আছে।
কৌতূহলী

1
এখানে পার্থক্যটি ইউবি বনাম আক্ষরিক অসম্ভব। সি ++ তে এমন কোনও সিনট্যাক্স নেই যা আপনাকে কোন রেফারেন্স পয়েন্টগুলিতে পরিবর্তন করতে দেয়।

অসম্ভব, কঠিন নয়, আপনি কেবলমাত্র সেই সূচকটির মেমরি অঞ্চলটি অ্যাক্সেস করতে পারেন যা সেই রেফারেন্সকে মডেলিং করে এবং এর সামগ্রী পরিবর্তন করতে পারে। এটা অবশ্যই করা যেতে পারে।
নিকোলাস বসকোয়েট

125

জনপ্রিয় মতামতের বিপরীতে, কোনও রেফারেন্স পাওয়া যায় যা NUL।

int * p = NULL;
int & r = *p;
r = 1;  // crash! (if you're lucky)

মঞ্জুর, একটি রেফারেন্স সহ এটি করা খুব শক্ত - তবে আপনি যদি এটি পরিচালনা করেন তবে আপনি এটির চেষ্টা করার জন্য আপনার চুল ছিঁড়ে ফেলবেন। তথ্যসূত্রগুলি সি ++ তে অন্তর্নিহিত নিরাপদ নয় !

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

প্রকৃত ত্রুটিটি কোনও রেফারেন্সের আগে বরাদ্দকরণের আগে NULL পয়েন্টারকে ডেরফেরিংয়ের মধ্যে রয়েছে। তবে আমি এমন কোনও সংকলক সম্পর্কে সচেতন নই যা এই শর্তে কোনও ত্রুটি তৈরি করবে - ত্রুটিটি কোডের পাশাপাশি আরও একটি পয়েন্টে প্রচার করে। এটাই এই সমস্যাটিকে এত কুখ্যাত করে তোলে। বেশিরভাগ সময়, আপনি যদি কোনও নল পয়েন্টারকে অবজ্ঞা করেন, আপনি ঠিক ঠিক সেই জায়গায় ক্র্যাশ হয়ে গিয়েছিলেন এবং এটি বের করতে খুব বেশি ডিবাগিং লাগে না।

আমার উপরের উদাহরণটি সংক্ষিপ্ত এবং স্বীকৃত। এখানে আরও একটি বাস্তব-বিশ্বের উদাহরণ।

class MyClass
{
    ...
    virtual void DoSomething(int,int,int,int,int);
};

void Foo(const MyClass & bar)
{
    ...
    bar.DoSomething(i1,i2,i3,i4,i5);  // crash occurs here due to memory access violation - obvious why?
}

MyClass * GetInstance()
{
    if (somecondition)
        return NULL;
    ...
}

MyClass * p = GetInstance();
Foo(*p);

আমি আবারও বলতে চাই যে নাল রেফারেন্স পাওয়ার একমাত্র উপায় হ'ল ত্রুটিযুক্ত কোডের মাধ্যমে, এবং একবার আপনার এটি হয়ে গেলে আপনি সংজ্ঞায়িত আচরণ পাচ্ছেন। এটা তোলে কখনো একটি নাল রেফারেন্সের জন্য চেক করতে ইন্দ্রিয় তোলে; উদাহরণস্বরূপ আপনি চেষ্টা করতে পারেন if(&bar==NULL)...তবে সংকলকটি অস্তিত্বের বাইরে থাকা বিবৃতিটিকে অনুকূল করতে পারে! একটি বৈধ রেফারেন্স কখনই নুল হতে পারে না তাই সংকলকের দর্শন থেকে তুলনাটি সর্বদা মিথ্যা এবং ifডেড কোড হিসাবে ধারাটি নির্মূল করা বিনামূল্যে - এটি অপরিবর্তিত আচরণের মূল বিষয়।

সমস্যা থেকে দূরে থাকার উপযুক্ত উপায় হ'ল একটি রেফারেন্স তৈরি করার জন্য কোনও NUL পয়েন্টারকে অবজ্ঞা করা এড়ানো। এটি সম্পাদন করার জন্য এখানে একটি স্বয়ংক্রিয় উপায়।

template<typename T>
T& deref(T* p)
{
    if (p == NULL)
        throw std::invalid_argument(std::string("NULL reference"));
    return *p;
}

MyClass * p = GetInstance();
Foo(deref(p));

আরও ভাল লেখার দক্ষতার সাথে কারও কাছ থেকে এই সমস্যাটি দেখার জন্য, জিম হিসলপ এবং হার্ব সটারের নাল রেফারেন্সগুলি দেখুন ।

নাল পয়েন্টারকে অবজ্ঞার বিপদের আরেকটি উদাহরণের জন্য দেখুন রেমন্ড চেনের অন্য প্ল্যাটফর্মে কোড পোর্ট করার সময় অপরিজ্ঞাত আচরণের প্রকাশ করা


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

9
চিহ্নটির একটি বৈধ যুক্তি রয়েছে। যে পয়েন্টারটি নুল হতে পারে এবং এর জন্য আপনাকে যাচাই করতে হবে সে যুক্তিটি আসল নয়: আপনি যদি বলেন যে কোনও ফাংশনটির জন্য অ-নুল প্রয়োজন হয়, তবে ফোনকারীকে তা করতে হবে। সুতরাং যদি কলার না করেন তবে তিনি অনির্ধারিত আচরণের জন্য আহ্বান করছেন। ঠিক চিহ্নটি খারাপ রেফারেন্সের সাথে করেছিল
জোহানেস স্কাউব - ২১

13
বর্ণনাটি ভ্রান্ত। এই কোডটি হয়ত বা এমন একটি রেফারেন্স তৈরি করতে পারে যা নুল UL এর আচরণ নির্ধারিত। এটি পুরোপুরি বৈধ রেফারেন্স তৈরি করতে পারে। এটি কোনও রেফারেন্স তৈরি করতে ব্যর্থ হতে পারে।
ডেভিড শোয়ার্জ

7
@ ডেভিড শোয়ার্জ, যদি আমি স্ট্যান্ডার্ড অনুযায়ী কাজ করার উপায় সম্পর্কে কথা বলতাম তবে আপনি সঠিক হয়ে উঠবেন। কিন্তু যে না আমি প্রকৃত পর্যবেক্ষিত আচরণ সম্পর্কে একটি খুব জনপ্রিয় কম্পাইলার সাথে কথা বলছি কি হবে টিপিক্যাল কম্পাইলার ও CPU আর্কিটেকচারের আমার জ্ঞানের ভিত্তিতে extrapolating, এবং - কি আমি যে বিষয়ে কথা বলছি সম্ভবত ঘটে। যদি আপনি বিশ্বাস করেন যে রেফারেন্সগুলি পয়েন্টারগুলির চেয়ে উচ্চতর বলে কারণ তারা নিরাপদ এবং উল্লেখগুলি খারাপ হতে পারে তা বিবেচনা না করে, আপনি যেমন ছিলাম ঠিক তেমনই কোনও একদিন সাধারণ সমস্যায় পড়ে যাবেন।
মার্ক র্যানসোম

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

114

আপনি সবচেয়ে গুরুত্বপূর্ণ অংশটি ভুলে গেছেন:

পয়েন্টার সহ ->
সদস্য অ্যাক্সেস রেফারেন্স ব্যবহারের সাথে সদস্য অ্যাক্সেস ব্যবহার করে.

foo.barহয় পরিষ্কারভাবে শ্রেয় foo->barএকই ভাবে যে হয় পরিষ্কারভাবে শ্রেয় গিয়ে Emacs :-)


4
@ অরিয়ন এডওয়ার্ডস> পয়েন্টারগুলির সাথে সদস্য অ্যাক্সেস ->> উল্লেখ ব্যবহারের সাথে সদস্য অ্যাক্সেস। এটি 100% সত্য নয়। আপনার একটি পয়েন্টারের রেফারেন্স থাকতে পারে। এক্ষেত্রে আপনি পরবর্তী -> স্ট্রাক্ট নোড {নোড * ব্যবহার করে ডি-রেফারেন্সড পয়েন্টারের সদস্যদের অ্যাক্সেস করতে পারবেন; }; নোড * প্রথম; // পি হ'ল একটি পয়েন্টার শূন্য ফু (নোড * & পি) a পি-> পরবর্তী = প্রথম; Ode নোড * বার = নতুন নোড; foo বিন্যাস (বার); - ওপি: আপনি কি রেভ্যালু এবং লভ্য ধারণাগুলির সাথে পরিচিত?

3
স্মার্ট পয়েন্টার দুটি আছে। (স্মার্ট পয়েন্টার শ্রেণিতে পদ্ধতি) এবং -> (অন্তর্নিহিত ধরণের পদ্ধতি) methods
জেবিআরউইলকিনসন

1
@ ইউজার 6105 ওরিওন এডওয়ার্ডস স্টেটমেন্টটি আসলে 100% সত্য। "ডি-রেফারেন্সড পয়েন্টারের সদস্যদের অ্যাক্সেস করুন" একটি পয়েন্টারের কোনও সদস্য থাকে না। পয়েন্টারটি যে অবজেক্টটিকে নির্দেশ করে তার সদস্য থাকে এবং সেগুলিতে অ্যাক্সেস হুবহু ->পয়েন্টারগুলিকে রেফারেন্স সরবরাহ করে ঠিক যেমন পয়েন্টার নিজেই।
সর্বোচ্চ ট্রুক্স

1
এটি কেন .এবং ->vi এবং
ইমাস

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

73

রেফারেন্সগুলি পয়েন্টারগুলির সাথে খুব মিল, তবে তারা সংকলকগুলির অনুকূলকরণে সহায়ক হতে বিশেষভাবে তৈরি করা হয়।

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

উদাহরণ হিসাবে:

void maybeModify(int& x); // may modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // This function is designed to do something particularly troublesome
    // for optimizers. It will constantly call maybeModify on array[0] while
    // adding array[1] to array[2]..array[size-1]. There's no real reason to
    // do this, other than to demonstrate the power of references.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(array[0]);
        array[i] += array[1];
    }
}

একটি অনুকূলকরণ সংকলক বুঝতে পারে যে আমরা একটি [0] এবং একটি [1] বেশ গুচ্ছ অ্যাক্সেস করছি। এটি এতে অ্যালগরিদমকে অনুকূল করতে পছন্দ করবে:

void hurtTheCompilersOptimizer(short size, int array[])
{
    // Do the same thing as above, but instead of accessing array[1]
    // all the time, access it once and store the result in a register,
    // which is much faster to do arithmetic with.
    register int a0 = a[0];
    register int a1 = a[1]; // access a[1] once
    for (int i = 2; i < (int)size; i++) {
        maybeModify(a0); // Give maybeModify a reference to a register
        array[i] += a1;  // Use the saved register value over and over
    }
    a[0] = a0; // Store the modified a[0] back into the array
}

এই ধরনের একটি অপ্টিমাইজেশন করতে, এটি প্রমাণ করতে হবে যে কল করার সময় অ্যারে [1] কিছুই পরিবর্তন করতে পারে না। এটি করা বরং বরং সহজ। আমি কখনই 2 এর চেয়ে কম নয়, সুতরাং অ্যারে [i] কখনও অ্যারে [1] উল্লেখ করতে পারে না। হতে পারে মোডিফাই () কে রেফারেন্স হিসাবে aliasing দেওয়া হয় (aliasing অ্যারে [0])। কোনও "রেফারেন্স" পাটিগণিত না থাকায়, সংকলকটি কেবল প্রমাণ করতে হয়েছিল যে সম্ভবতমাডিফাই কখনও x এর ঠিকানা পায় না এবং এটি প্রমাণিত হয়েছে যে কিছুই অ্যারে পরিবর্তন করে না [1]

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

এখন পয়েন্টার দিয়ে একই জিনিস

void maybeModify(int* x); // May modify x in some way

void hurtTheCompilersOptimizer(short size, int array[])
{
    // Same operation, only now with pointers, making the
    // optimization trickier.
    for (int i = 2; i < (int)size; i++) {
        maybeModify(&(array[0]));
        array[i] += array[1];
    }
}

আচরণ একই; কেবলমাত্র এখন প্রমাণ করা অনেক কঠিন যে সম্ভবতমাডিফাই কখনও অ্যারে পরিবর্তন করে না [1], কারণ আমরা ইতিমধ্যে এটি একটি পয়েন্টার দিয়েছি; বিড়াল থলের মধ্য থেকে বের হয়. এখন এটি আরও জটিল প্রমাণ করতে হবে: এটি সম্ভবত & x + 1 তে কখনও লেখেন না তা প্রমাণ করার জন্য মডফাইফের একটি স্ট্যাটিক বিশ্লেষণ এটি প্রমাণ করতে হবে যে এটি অ্যারে [0] উল্লেখ করতে পারে এমন কোনও পয়েন্টারটি কখনও সংরক্ষণ করে না, যা ঠিক কৌতুকময়

আধুনিক সংকলক স্থিতিশীল বিশ্লেষণে আরও ভাল এবং উন্নত হচ্ছে তবে তাদের সাহায্য করার জন্য এবং উল্লেখগুলি ব্যবহার করার জন্য এটি সর্বদা দুর্দান্ত।

অবশ্যই, এই ধরনের চৌকস অপটিমাইজেশন বাদ দিয়ে, সংকলকগণ যখন প্রয়োজন হবে তখন অবশ্যই রেফারেন্সগুলিকে পয়েন্টারে পরিণত করবে।

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

F createF(int argument);

void extending()
{
    const F& ref = createF(5);
    std::cout << ref.getArgument() << std::endl;
};

সাধারনত অস্থায়ী বস্তু যেমন কল দ্বারা তৈরি করা createF(5)অভিব্যক্তিটির শেষে ধ্বংস হয়। তবে, সেই বস্তুকে রেফারেন্সের সাথে আবদ্ধ করে ref, C ++ সেই অস্থায়ী অবজেক্টের আয়ু বাড়িয়ে দেবে যতক্ষণ না refসুযোগের বাইরে চলে যায়।


সত্য, শরীরটি দৃশ্যমান হতে হবে। যাইহোক, এটি সম্পর্কিত যে maybeModifyকোনও কিছুর ঠিকানা গ্রহণ করে না তা নির্ধারণ করা যে xএকগুচ্ছ পয়েন্টার গাণিতিক সংঘটিত হয় না তা প্রমাণ করার চেয়ে যথেষ্ট সহজ।
আম্মোনকে

আমি বিশ্বাস করি যে অপটিমাইজার ইতিমধ্যে এটি করেছে যে "গুচ্ছ পয়েন্টার গণিতটি ঘটে না" গুচ্ছ অন্যান্য কারণের জন্য পরীক্ষা করে দেখুন।
বেন ভয়েগট

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

আমার অনুভূতি আছে যে কেউ ভুলভাবে চিহ্নিত মন্তব্যটির মত করে অপ্রচলিত হিসাবে চিহ্নিত করেছে void maybeModify(int& x) { 1[&x]++; }, যা উপরের অন্যান্য মন্তব্যগুলি আলোচনা করছে
বেন ভয়েগ্ট

67

আসলে, একটি রেফারেন্স আসলে পয়েন্টারের মতো নয়।

একটি সংকলক একটি পরিবর্তনকে "রেফারেন্স" রাখে, একটি নামকে মেমোরি ঠিকানার সাথে যুক্ত করে; সংকলনের সময় কোনও ভেরিয়েবলের নাম কোনও মেমরি ঠিকানায় অনুবাদ করা এটাই তার কাজ।

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

পয়েন্টারগুলি ভেরিয়েবল হয়; এগুলিতে কিছু অন্যান্য ভেরিয়েবলের ঠিকানা থাকে বা শূন্য হতে পারে। গুরুত্বপূর্ণ বিষয়টি হল যে কোনও পয়েন্টারের একটি মান থাকে তবে একটি রেফারেন্সের কেবলমাত্র একটি চলক থাকে যা এটি উল্লেখ করা হয়।

এখন বাস্তব কোড সম্পর্কে কিছু ব্যাখ্যা:

int a = 0;
int& b = a;

এখানে আপনি অন্য ভেরিয়েবল তৈরি করছেন না যা নির্দেশ করে a; আপনি কেবল মানটির সাথে থাকা মেমরি সামগ্রীতে অন্য একটি নাম যুক্ত করছেন a। এই মেমরি এখন দুটি নাম আছে, aএবং b, এবং এটা হয় নাম ব্যবহার করে সম্বোধন করা যেতে পারে।

void increment(int& n)
{
    n = n + 1;
}

int a;
increment(a);

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

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


2
একটি রেফারেন্স হ'ল l- এর একটি রেফারেন্স, কোনও পরিবর্তনশীলের অগত্যা নয়। এ কারণে, এটি একটি আসল নাম (একটি সংকলন-সময় গঠন) এর চেয়ে পয়েন্টারের কাছে অনেক বেশি। যে রেফারেন্সগুলির উল্লেখ করা যেতে পারে তার উদাহরণগুলি হল * পি বা এমনকি * পি ++

5
ঠিক আছে, আমি কেবল এই বিষয়টির দিকে ইঙ্গিত করছিলাম যে কোনও রেফারেন্স সর্বদা একটি নতুন পয়েন্টারটি যেভাবে ইচ্ছা স্ট্যাকের উপরে একটি নতুন ভেরিয়েবলকে ঠেলাতে পারে না।
ভিনসেন্ট রবার্ট

1
@ ভিনসেন্টরোবার্ট: এটি পয়েন্টারের মতোই কাজ করবে ... যদি ফাংশনটি ইনলাইন করা হয় তবে রেফারেন্স এবং পয়েন্টার উভয়ই অপ্টিমাইজ করা হবে। যদি কোনও ফাংশন কল থাকে তবে অবজেক্টের ঠিকানাটি ফাংশনে প্রেরণ করা প্রয়োজন।
বেন ভয়েগট

1
int * p = NULL; int & r = * p; রেফারেন্স NULL নির্দেশ; if (r) {} -> boOm;)
শ্রী

2
সংকলনের পর্যায়ে এই ফোকাসটি দুর্দান্ত বলে মনে হচ্ছে, যতক্ষণ না আপনি মনে রাখবেন যে রানফল সময়ে রেফারেন্সগুলি প্রায় পাস করা যেতে পারে, যেখানে স্ট্যাটিক আলিয়াজিং উইন্ডোটির বাইরে চলে যায়। (এবং তারপরে, রেফারেন্সগুলি সাধারণত পয়েন্টার হিসাবে প্রয়োগ করা হয়, তবে মানটিকে এই পদ্ধতির প্রয়োজন হয় না))
আন্ডারস্কোর_১১

44

একটি রেফারেন্স কখনও হতে পারে NULL


10
একটি পাল্টা উদাহরণের জন্য মার্ক র্যানসমের উত্তর দেখুন। রেফারেন্স সম্পর্কে এটি প্রায়শই দৃserted়ভাবে প্রচলিত মিথ, তবে এটি একটি পৌরাণিক কাহিনী। স্ট্যান্ডার্ড অনুসারে আপনার কেবলমাত্র গ্যারান্টি হ'ল আপনার যখন কোনও NUL রেফারেন্স থাকে তখন সঙ্গে সঙ্গে আপনার ইউবি থাকে। কিন্তু যে বলার অপেক্ষা রাখে না সদৃশ হয় "এই গাড়ী নিরাপদ, এটি বন্ধ রাস্তা পেতে পারেন (আমরা যদি যাহাই হউক না কেন রাস্তা বন্ধ এটা বাহা কী ঘটতে পারে সে জন্য কোনো দায়িত্ব গ্রহণ না এটা ঠিক বিস্ফোরিত করা হতে পারে।।)।"
cmaster -

17
@ মাস্টার: একটি বৈধ প্রোগ্রামে , একটি রেফারেন্স নਾਲ হতে পারে না। কিন্তু একটি পয়েন্টার পারেন। এটি কোনও পৌরাণিক কাহিনী নয়, এটি একটি সত্য।
ব্যবহারকারী541686

8
@ মেহরদাদ হ্যাঁ, বৈধ প্রোগ্রামগুলি রাস্তায় থাকবে। তবে বাস্তবায়ন করতে কোনও ট্র্যাফিক বাধা নেই যা আপনার প্রোগ্রামটি আসলে করে। রাস্তার বড় অংশগুলি চিহ্নিত চিহ্নগুলি হারিয়েছে। তাই রাস্তায় রাস্তায় নামা চূড়ান্ত সহজ। এবং এই জাতীয় বাগগুলি ডিবাগ করার জন্য এটি গুরুত্বপূর্ণ যে আপনি জানেন যে এটি ঘটতে পারে: নাল রেফারেন্সটি আপনার প্রোগ্রামটিকে ক্র্যাশ করার আগে নাল রেফারেন্সটি প্রচার করতে পারে ঠিক যেমন নাল পয়েন্টারটি পারে। এবং যখন এটি আপনার কাছে void Foo::bar() { virtual_baz(); }সেগফাল্টের মতো কোড থাকে । যদি আপনি সচেতন না হন যে উল্লেখগুলি নালাগুলি হতে পারে তবে আপনি শূন্যটিকে এর উত্সটিতে ফিরে পেতে পারবেন না।
সিমেস্টার

4
int * p = NULL; int & r = * p; রেফারেন্স NULL নির্দেশ; if (r) {} -> boOm;) -
শ্রী

10
@ শ্রী int &r=*p;হ'ল অপরিজ্ঞাত আচরণ। এই মুহুর্তে, আপনি একটি নেই "শূন্য রেফারেন্স ইশারা," যদি আপনি একটি প্রোগ্রাম আছে আর সম্পর্কে কারণগত যাবে এ সব
cdowie

34

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

এই দুটি প্রোগ্রামের টুকরো বিবেচনা করুন। প্রথমটিতে, আমরা অন্যকে একটি পয়েন্টার বরাদ্দ করি:

int ival = 1024, ival2 = 2048;
int *pi = &ival, *pi2 = &ival2;
pi = pi2;    // pi now points to ival2

অ্যাসাইনমেন্টের পরে, iv, পাই দ্বারা সম্বোধিত বস্তুটি অপরিবর্তিত রয়েছে। অ্যাসাইনমেন্টটি পাইয়ের মান পরিবর্তন করে, এটি অন্য কোনও বস্তুর দিকে নির্দেশ করে। এখন একটি অনুরূপ প্রোগ্রাম বিবেচনা করুন যা দুটি রেফারেন্স নির্ধারণ করে:

int &ri = ival, &ri2 = ival2;
ri = ri2;    // assigns ival2 to ival

এই অ্যাসাইনমেন্টটি আইভেলকে পরিবর্তন করে, রি দ্বারা রেফারেন্স করা মান, এবং নিজেই রেফারেন্সটি নয়। অ্যাসাইনমেন্টের পরে, দুটি রেফারেন্স এখনও তাদের মূল বস্তুগুলিকে বোঝায় এবং objects বস্তুর মানও এখন একইরকম।


"একটি রেফারেন্স সর্বদা একটি অবজেক্টকে বোঝায়" কেবল সম্পূর্ণ মিথ্যা
বেন ভয়েগট

31

আপনি যদি কোনও বিমূর্ত বা এমনকি একাডেমিক ফ্যাশনে কম্পিউটারের ভাষা অধ্যয়নের সাথে পরিচিত না হন তবে একটি অর্থগত পার্থক্য রয়েছে es

সর্বোচ্চ স্তরে, রেফারেন্সগুলির ধারণাটি হ'ল তারা স্বচ্ছ "এলিয়াস"। আপনার কম্পিউটারটি তাদের কাজ করার জন্য কোনও ঠিকানা ব্যবহার করতে পারে, তবে আপনাকে এটি নিয়ে চিন্তিত হওয়ার কথা নয়: আপনি তাদের কোনও বিদ্যমান বস্তুর জন্য "কেবলমাত্র অন্য একটি নাম" হিসাবে ভাবেন এবং সিনট্যাক্সটি সেটিকে প্রতিফলিত করে। এগুলি পয়েন্টারের তুলনায় আরও কঠোর, যাতে আপনি যখন ঝোলা ঝুঁকিপূর্ণ পয়েন্টার তৈরি করতে যাবেন তার চেয়ে আপনার সংকলক আপনাকে আরও নির্ভরযোগ্যভাবে সতর্ক করতে পারে।

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


26

একটি রেফারেন্স অন্য ভেরিয়েবলের জন্য একটি উপাম যেখানে একটি পয়েন্টার একটি ভেরিয়েবলের মেমরি ঠিকানা রাখে। রেফারেন্সগুলি সাধারণত ফাংশন প্যারামিটার হিসাবে ব্যবহৃত হয় যাতে পাস করা বস্তুটি অনুলিপি নয় বরং নিজেই object

    void fun(int &a, int &b); // A common usage of references.
    int a = 0;
    int &b = a; // b is an alias for a. Not so common to use. 

19

এটি কতটা জায়গা নেয় তা বিবেচনাধীন নয় যেহেতু আপনি যে জায়গাতেই গ্রহণ করবেন তা বাস্তবে কোনও পার্শ্ব প্রতিক্রিয়া (কোড প্রয়োগ না করে) দেখতে পাচ্ছেন না।

অন্যদিকে, রেফারেন্স এবং পয়েন্টারগুলির মধ্যে একটি প্রধান পার্থক্য হ'ল কনস্টের রেফারেন্সকে সীমাবদ্ধ না করা পর্যন্ত কনস্টের রেফারেন্সগুলিকে অর্পণ করা টেম্পোরারিগুলি লাইভ থাকে।

উদাহরণ স্বরূপ:

class scope_test
{
public:
    ~scope_test() { printf("scope_test done!\n"); }
};

...

{
    const scope_test &test= scope_test();
    printf("in scope\n");
}

মুদ্রণ করবে:

in scope
scope_test done!

এটি সেই ভাষা পদ্ধতি যা স্কোপগার্ডকে কাজ করতে দেয়।


1
আপনি কোনও রেফারেন্সের ঠিকানা নিতে পারবেন না, তবে এর অর্থ এই নয় যে তারা শারীরিকভাবে স্থান গ্রহণ করেন না। অপ্টিমাইজেশন বাদে তারা অবশ্যই তা পারে।
অরবিট

2
প্রভাব সত্ত্বেও, "স্ট্যাকের উপর একটি রেফারেন্স মোটেও কোনও স্থান নেয় না" স্পষ্টতই মিথ্যা।
অরবিট

1
@ তোমালাক, ভাল, এটি সংকলকটির উপরও নির্ভর করে। তবে হ্যাঁ, এটি কিছুটা বিভ্রান্তিকর। আমি মনে করি এটি সরিয়ে ফেলতে কম বিভ্রান্তি হবে।
এমএসএএন

1
যে কোনও নির্দিষ্ট ক্ষেত্রে এটি হতে পারে বা নাও পারে। সুতরাং "এটি হয় না" যেমন একটি স্পষ্টিকর বক্তব্য ভুল। সেটাই আমি বলছি. :) [আমি স্ট্যান্ডার্ড ইস্যুতে কি বলে মনে করতে পারি না; রেফারেন্স সদস্যদের নিয়মগুলি "রেফারেন্স স্থান নিতে পারে" এর একটি সাধারণ নিয়ম জারি করতে পারে, তবে সৈকতে আমার কাছে আমার কাছে স্ট্যান্ডার্ডটির অনুলিপিটি নেই: ডি]
অরবিট

19

এটি টিউটোরিয়াল ভিত্তিক । যা লেখা আছে তা আরও স্পষ্ট করে তোলে:

>>> The address that locates a variable within memory is
    what we call a reference to that variable. (5th paragraph at page 63)

>>> The variable that stores the reference to another
    variable is what we call a pointer. (3rd paragraph at page 64)

কেবল এটি মনে রাখা,

>>> reference stands for memory location
>>> pointer is a reference container (Maybe because we will use it for
several times, it is better to remember that reference.)

আরও কী, আমরা প্রায় যে কোনও পয়েন্টার টিউটোরিয়ালটি উল্লেখ করতে পারি, পয়েন্টার হ'ল পয়েন্টার এমন একটি বস্তু যা পয়েন্টার পাটিগণিত দ্বারা সমর্থিত যা পয়েন্টারকে অ্যারের অনুরূপ করে তোলে।

নিম্নলিখিত বিবৃতি দেখুন,

int Tom(0);
int & alias_Tom = Tom;

alias_Tomএকটি হিসাবে বোঝা যায় alias of a variable( typedefযার সাথে পৃথক হয় alias of a type) Tom। এ জাতীয় বিবৃতিটির পরিভাষাটি একটি রেফারেন্স তৈরি করা ভুলে যাওয়াও ঠিক Tom


1
এবং যদি কোনও শ্রেণীর একটি রেফারেন্স ভেরিয়েবল থাকে তবে এটি আরম্ভের তালিকায় একটি নলপ্টর বা একটি বৈধ অবজেক্টের সাহায্যে সূচনা করা উচিত।
Misgevolution

1
এই উত্তরের শব্দটি এটির সত্যিকারের ব্যবহারের জন্য খুব বিভ্রান্তিকর। এছাড়াও, @ মিসেজভলিউশন, আপনি কি পাঠকদের একটির সাথে একটি রেফারেন্স শুরু করার জন্য গুরুত্ব সহকারে সুপারিশ করছেন nullptr? আপনি আসলে এই থ্রেডের অন্য কোনও অংশ পড়েছেন, বা ...?
আন্ডারস্কোর_১১

1
আমার খারাপ, আমি যে বোকা জিনিস বলেছি তার জন্য দুঃখিত। ততক্ষণে আমার ঘুম অবশ্যই বঞ্চিত ছিল। 'নালপ্ট্রার দিয়ে ইনিশিয়ালাইজ করা' সম্পূর্ণ ভুল।
মিসেজভোলিউশন

18

একটি রেফারেন্স কিছু স্মৃতিতে দেওয়া অন্য নাম নয়। এটি একটি অপরিবর্তনীয় পয়েন্টার যা স্বয়ংক্রিয়ভাবে ব্যবহারে ডি-রেফারেন্সেড। মূলত এটি নিচে ফোটে:

int& j = i;

এটি অভ্যন্তরীণ হয়ে যায়

int* const j = &i;

13
এটি সি ++ স্ট্যান্ডার্ড যা বলে তা নয় এবং সংকলকটির জন্য আপনার উত্তর দ্বারা বর্ণিত পদ্ধতিতে রেফারেন্সগুলি প্রয়োগ করা প্রয়োজন হয় না।
jogojapan

@ জোগোজাপান: সি ++ কম্পাইলারের জন্য কোনও রেফারেন্স বাস্তবায়নের জন্য বৈধ যে কোনও উপায়ে এটি constপয়েন্টার বাস্তবায়নের জন্য একটি বৈধ উপায় । এই নমনীয়তা প্রমাণ করে না যে একটি রেফারেন্স এবং পয়েন্টারের মধ্যে পার্থক্য রয়েছে।
বেন ভয়েগট

2
@ বেনভয়েগ্ট এটি সত্য হতে পারে যে কোনও একটি বৈধ বাস্তবায়নও অন্যটির বৈধ বাস্তবায়ন, তবে এটি এই দুটি ধারণার সংজ্ঞা থেকে সুস্পষ্ট উপায়ে অনুসরণ করে না। একটি ভাল উত্তর সংজ্ঞাগুলি থেকে শুরু হত, এবং প্রদর্শিত হয়েছিল যে দু'জনের সম্পর্কে দাবী শেষ পর্যন্ত একই কেন। এই উত্তরটি অন্য কয়েকটি উত্তরের উপর একরকম মন্তব্য বলে মনে হচ্ছে।
jogojapan

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

17

সরাসরি উত্তর

সি ++ এ একটি রেফারেন্স কী? টাইপের কিছু নির্দিষ্ট উদাহরণ যা কোনও অবজেক্ট টাইপ নয়

সি ++ এর পয়েন্টার কী? টাইপের কিছু নির্দিষ্ট উদাহরণ যা একটি অবজেক্ট টাইপ

থেকে অবজেক্টের তালিকায় আইএসও সি ++ সংজ্ঞা :

একটি অবজেক্ট টাইপ হ'ল (সম্ভবত সিভি- কোয়ালিফাইড) টাইপ যা কোনও ফাংশন টাইপ নয়, রেফারেন্স টাইপ নয়, সিভি অকার্যকর নয়।

এটি জেনে রাখা জরুরী হতে পারে, অবজেক্ট টাইপ হ'ল সি ++ তে মহাবিশ্বের ধরণের একটি শীর্ষ স্তরের বিভাগ। রেফারেন্সটিও একটি শীর্ষ স্তরের বিভাগ। তবে পয়েন্টারটি হয় না।

যৌগিক ধরণের প্রসঙ্গে পয়েন্টার এবং রেফারেন্সগুলি একসাথে উল্লেখ করা হয়েছে । এটি মূলত (এবং প্রসারিত) সি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত ঘোষক সিনট্যাক্সের প্রকৃতির কারণে, যার কোনও উল্লেখ নেই। (তদ্ব্যতীত, সি ++ ১১ এর পরে একাধিক ধরণের রেফারেন্সার রয়েছে, যদিও পয়েন্টারগুলি এখনও "unityক্যবদ্ধ": &+ &&বনাম *।) সুতরাং এই প্রসঙ্গে সি এর অনুরূপ শৈলীর সাথে "এক্সটেনশন" দ্বারা নির্দিষ্ট একটি ভাষা খসড়া কিছুটা যুক্তিসঙ্গত । (আমি এখনও তর্ক করব যে ঘোষকগণের বাক্য গঠন সিনট্যাক্টিক ভাব প্রকাশকে প্রচুর অপচয় করে , মানব ব্যবহারকারী এবং বাস্তবায়ন উভয়ই হতাশ করে তোলে Thus সুতরাং, এগুলি সমস্তই অন্তর্নির্মিত হওয়ার যোগ্য নয়)একটি নতুন ভাষা নকশা। এটি পিএল ডিজাইন সম্পর্কে সম্পূর্ণ ভিন্ন বিষয়, যদিও))

অন্যথায়, এটি নগণ্য যে পয়েন্টারগুলি একসাথে রেফারেন্স সহ নির্দিষ্ট ধরণের ধরণের হিসাবে যোগ্য হতে পারে। এগুলি সিনট্যাক্সের মিলের পাশাপাশি খুব কম সাধারণ বৈশিষ্ট্যগুলি ভাগ করে, তাই বেশিরভাগ ক্ষেত্রে এগুলি একত্রে রাখার দরকার নেই।

উপরের বিবৃতিগুলিতে কেবল "পয়েন্টার" এবং "রেফারেন্স" প্রকার হিসাবে উল্লেখ করুন নোট করুন। তাদের দৃষ্টান্তগুলি সম্পর্কে কিছু আগ্রহী প্রশ্ন রয়েছে (যেমন ভেরিয়েবল)। অনেকগুলি ভুল ধারণাও আসে।

শীর্ষ-স্তরের বিভাগগুলির পার্থক্য ইতিমধ্যে অনেকগুলি কংক্রিটের পার্থক্য প্রকাশ করতে পারে যেগুলি সরাসরি পয়েন্টারগুলিতে আবদ্ধ নয়:

  • অবজেক্টের ধরণের শীর্ষ স্তরের cvযোগ্যতা থাকতে পারে। তথ্যসূত্রগুলি পারে না।
  • বিমূর্ত মেশিন শব্দার্থবিজ্ঞানের অনুযায়ী অবজেক্টের ধরণের পরিবর্তনশীল স্টোরেজ দখল করে । রেফারেন্সটি স্টোরেজ দখল করার প্রয়োজন নেই (বিশদগুলির জন্য নীচের ভুল ধারণা সম্পর্কে বিভাগটি দেখুন)।
  • ...

তথ্যসূত্র সম্পর্কে আরও কয়েকটি বিশেষ বিধি:

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

ভুল ধারণা

সিনট্যাকটিক চিনি

আমি জানি রেফারেন্সগুলি সিনট্যাকটিক চিনি, তাই কোড পড়া এবং লেখা সহজ।

প্রযুক্তিগতভাবে, এটি সাধারণ ভুল। রেফারেন্সগুলি সি ++ তে অন্য কোনও বৈশিষ্ট্যের সিনট্যাকটিক চিনির নয়, কারণ সেগুলি কোনও সিন্থেটিক পার্থক্য ছাড়াই অন্য বৈশিষ্ট্যগুলি দ্বারা ঠিক প্রতিস্থাপন করা যায় না।

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

এই কঠোর অর্থে সি ++ এর কয়েক ধরণের সিনট্যাকটিক সুগার রয়েছে। একটি উদাহরণ হ'ল (সি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত) বিল্ট-ইন (অ-ওভারলোডেড) অপারেটর [], যা বিল্ট-ইন অপারেটর অ্যানারি *এবং বাইনারিগুলির উপর নির্দিষ্ট ফর্মের সংমিশ্রণের একই শব্দার্থক বৈশিষ্ট্যগুলি সংজ্ঞায়িত করা হয়েছে+

সংগ্রহস্থল

সুতরাং, একটি পয়েন্টার এবং একটি রেফারেন্স উভয় একই পরিমাণে মেমরি ব্যবহার করে।

উপরের বিবৃতিটি কেবল ভুল। এই ধরনের ভুল ধারণা এড়াতে, পরিবর্তে আইএসও সি ++ বিধিগুলি দেখুন:

থেকে [intro.object] / 1 :

... একটি অবজেক্ট তার নির্মাণকালের পুরো সময়কালে এবং তার ধ্বংসের সময়কালে স্টোরেজের একটি অঞ্চল দখল করে। ...

থেকে [dcl.ref] / 4 :

কোনও রেফারেন্সের স্টোরেজ প্রয়োজন কিনা তা অনির্দিষ্ট।

এগুলি অর্থপূর্ণ বৈশিষ্ট্যগুলি নোট করুন ।

Pragmatics

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

তবে এটি পুরো গল্প নয়। আমি বলতে চাইছি, পয়েন্টার বনাম রেফারেন্সের তুলনায় আপনার আরও অনেকগুলি বিষয় রয়েছে consider

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

  • কখনও কখনও ভাষার নিয়মের স্পষ্টভাবে নির্দিষ্ট ধরণের ব্যবহারের প্রয়োজন হয়। আপনি যদি এই বৈশিষ্ট্যগুলি ব্যবহার করতে চান তবে নিয়ম মানুন।
    • অনুলিপি নির্মাণকারীদের 1 ম প্যারামিটার ধরণের হিসাবে নির্দিষ্ট ধরণের সিভি - &রেফারেন্সের ধরণের প্রয়োজন। (এবং সাধারণত এটি constযোগ্যতা অর্জন করা উচিত ।)
    • মুভ কনস্ট্রাক্টরগুলির 1 ম প্যারামিটার ধরণের হিসাবে নির্দিষ্ট ধরণের সিভি - &&রেফারেন্স টাইপ প্রয়োজন require (এবং সাধারণত কোনও বাছাইকারী হওয়া উচিত নয়))
    • অপারেটরগুলির নির্দিষ্ট ওভারলোডগুলির জন্য রেফারেন্স বা অ রেফারেন্স ধরণের প্রয়োজন। উদাহরণ স্বরূপ:
      • operator=বিশেষ সদস্য ফাংশন হিসাবে ওভারলোডডের জন্য অনুলিপি / মুভ কনস্ট্রাক্টরের 1 ম প্যারামিটারের অনুরূপ রেফারেন্স প্রকারের প্রয়োজন হয়।
      • পোস্টফিক্সের ++ডামি দরকার int
      • ...
  • আপনি যদি জানেন যে পাস-বাই-ভ্যালু (অর্থাত্ রেফারেন্সবিহীন প্রকারের ব্যবহার করা) যথেষ্ট, তবে এটি সরাসরি ব্যবহার করুন, বিশেষত যখন C ++ 17 বাধ্যতামূলক অনুলিপি সমর্থনকারী একটি বাস্তবায়ন ব্যবহার করছেন। ( সতর্কতা : তবে প্রয়োজনীয়তার বিষয়ে নিখুঁতভাবে যুক্তি যুক্ত করা খুব জটিল হতে পারে ।)
  • আপনি যদি মালিকানার সাথে কিছু হ্যান্ডলগুলি পরিচালনা করতে চান তবে কাঁচা পয়েন্টারগুলির পরিবর্তে স্মার্ট পয়েন্টারগুলি unique_ptrএবং shared_ptr(বা এমনকি যদি হোমব্রিউগুলির সাথে যদি আপনার অস্বচ্ছ প্রয়োজন হয় তবে ) ব্যবহার করুন।
  • আপনি যদি কোনও পরিসীমা জুড়ে কিছু পুনরাবৃত্তি করছেন, তবে কাঁচা পয়েন্টারগুলি নিশ্চিত না করে কাঁচা পয়েন্টারগুলি তুলনায় কাঁচা পয়েন্টারগুলি না করে (যেমন কম শিরোনাম নির্ভরতার জন্য) খুব সুনির্দিষ্টভাবে কাঁচা পয়েন্টারগুলি না রেখে আইট্রেটরগুলি (বা কিছু রেঞ্জ যা এখনও স্ট্যান্ডার্ড লাইব্রেরি দ্বারা সরবরাহ করা হয়নি) ব্যবহার করুন মামলা।
  • আপনি যদি জানেন যে পাস-বাই-মানটি যথেষ্ট এবং আপনি কিছু স্পষ্টভাবে নালামযোগ্য শব্দার্থক শব্দ চান std::optional, তবে কাঁচা পয়েন্টারগুলির পরিবর্তে মোড়কের মতো ব্যবহার করুন ।
  • যদি আপনি জানেন যে উপরোক্ত কারণে পাস-বাই-মানটি আদর্শ নয়, এবং আপনি নমনীয় শব্দার্থবিজ্ঞান চান না, {lvalue, rvalue, forwarding} -ferences উল্লেখ করুন।
  • আপনি যখন চিরাচরিত পয়েন্টারের মতো শব্দার্থক শব্দগুলি চান তখনও observer_ptrলাইব্রেরি ফান্ডামেন্টাল টিএস এর মতো প্রায়শই আরও উপযুক্ত কিছু থাকে ।

কেবলমাত্র ব্যতিক্রমগুলি বর্তমান ভাষায় কাজ করা যায় না:

  • আপনি যখন উপরের স্মার্ট পয়েন্টারগুলি বাস্তবায়ন করছেন তখন আপনাকে কাঁচা পয়েন্টারগুলি মোকাবেলা করতে হতে পারে।
  • নির্দিষ্ট ভাষা-আন্তঃব্যবস্থা রুটিনগুলির জন্য পয়েন্টারগুলির মতো প্রয়োজন operator new। (তবে, সিভি - void*সাধারণ অবজেক্ট পয়েন্টারগুলির তুলনায় এখনও বেশ আলাদা এবং সুরক্ষিত কারণ এটি অপ্রত্যাশিত পয়েন্টার পাটিগণিতকে বাতিল করে দেয় যদি না আপনি জিএনইউর মতো কিছু অবিস্মরণীয় এক্সটেনশানের উপর নির্ভর না করেন void*।)
  • ফাংশন পয়েন্টারগুলি ক্যাপচার ব্যতীত ল্যাম্বডা এক্সপ্রেশন থেকে রূপান্তর করা যায়, যখন ফাংশন উল্লেখগুলি পারে না। আপনাকে এই জাতীয় ক্ষেত্রে নন-জেনেরিক কোডে ফাংশন পয়েন্টার ব্যবহার করতে হবে, এমনকি আপনি ইচ্ছাকৃতভাবে মূল্যহীন মান চান না।

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

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

ভাষা নিরপেক্ষতা সতর্কতা

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

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

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

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

(একটি পক্ষের নোট: ALGOL 68 বনাম পিএল / আই এর মতো যে কোনও "সি-জাতীয়" ভাষা জড়িত রয়েছে তার চেয়ে আগে প্রশ্নটি উল্লেখযোগ্য হতে পারে ))


16

সি ++ তে পয়েন্টারের একটি রেফারেন্স সম্ভব, তবে বিপরীতটি সম্ভব নয় মানে একটি রেফারেন্সের পয়েন্টার দেওয়া সম্ভব নয়। পয়েন্টারের একটি রেফারেন্স পয়েন্টারটি সংশোধন করতে একটি ক্লিনার সিনট্যাক্স সরবরাহ করে। এই উদাহরণটি দেখুন:

#include<iostream>
using namespace std;

void swap(char * &str1, char * &str2)
{
  char *temp = str1;
  str1 = str2;
  str2 = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap(str1, str2);
  cout<<"str1 is "<<str1<<endl;
  cout<<"str2 is "<<str2<<endl;
  return 0;
}

এবং উপরের প্রোগ্রামটির সি সংস্করণটি বিবেচনা করুন। সিতে আপনাকে পয়েন্টার থেকে পয়েন্টার (একাধিক দিকনির্দেশ) ব্যবহার করতে হবে এবং এটি বিভ্রান্তির দিকে নিয়ে যায় এবং প্রোগ্রামটি জটিল দেখায়।

#include<stdio.h>
/* Swaps strings by swapping pointers */
void swap1(char **str1_ptr, char **str2_ptr)
{
  char *temp = *str1_ptr;
  *str1_ptr = *str2_ptr;
  *str2_ptr = temp;
}

int main()
{
  char *str1 = "Hi";
  char *str2 = "Hello";
  swap1(&str1, &str2);
  printf("str1 is %s, str2 is %s", str1, str2);
  return 0;
}

পয়েন্টারের রেফারেন্স সম্পর্কে আরও তথ্যের জন্য নিম্নলিখিতটি দেখুন:

আমি যেমন বলেছি, একটি রেফারেন্সের পয়েন্টার সম্ভব নয়। নিম্নলিখিত প্রোগ্রাম চেষ্টা করুন:

#include <iostream>
using namespace std;

int main()
{
   int x = 10;
   int *ptr = &x;
   int &*ptr1 = ptr;
}

15

আমার এইগুলির কোনওটির প্রয়োজন না হলে আমি রেফারেন্স ব্যবহার করি:

  • নাল পয়েন্টারগুলি সেন্ডিনেল মান হিসাবে ব্যবহার করা যেতে পারে, প্রায়শই ফাংশন ওভারলোডিং বা বুলের ব্যবহার এড়ানোর জন্য একটি সস্তা উপায়।

  • আপনি একটি পয়েন্টারে গাণিতিক করতে পারেন। উদাহরণ স্বরূপ,p += offset;


5
রেফারেন্স হিসাবে ঘোষিত হয়েছিল &r + offsetযেখানে আপনি লিখতে পারেনr
এমএম

14

পয়েন্টার এবং রেফারেন্সের মধ্যে একটি মৌলিক পার্থক্য রয়েছে যা আমি কারও উল্লেখ করে দেখিনি: উল্লেখগুলি ফাংশন আর্গুমেন্টগুলিতে পাস-রেফারেন্স শব্দার্থকে সক্ষম করে enable পয়েন্টারগুলি, যদিও এটি প্রথমে দৃশ্যমান নয় তা নয়: তারা কেবল পাস-বাই-ভ্যালু শব্দার্থবিদ্যা সরবরাহ করে। এটি এই নিবন্ধে খুব সুন্দরভাবে বর্ণনা করা হয়েছে ।

শুভেচ্ছা, & rzej


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

আমিও এরকম ভাবতাম। তবে লিঙ্কযুক্ত নিবন্ধটি কেন তা নয় তা বর্ণনা করে দেখুন।
আন্দ্রেজেজ

2
@ আন্ডারজ: এটি আমার মন্তব্যে একক বাক্যটির খুব দীর্ঘ সংস্করণ: হ্যান্ডেলটি অনুলিপি করা হয়েছে।
বেন ভয়েগট

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

1
@ আন্দ্রেজেজ মিথ্যা উভয় ক্ষেত্রেই, পাস-বাই-মান ঘটে চলেছে। রেফারেন্সটি মান দ্বারা পাস হয় এবং পয়েন্টারটি মান দ্বারা পাস হয়। অন্যথায় বললে নবাগত বিভ্রান্ত হয়।
মাইলস রাউট

13

বিভ্রান্তি যুক্ত হওয়ার ঝুঁকিতে, আমি কিছু ইনপুট ফেলতে চাই, আমি নিশ্চিত যে এটি প্রায়শই সংকলকটি রেফারেন্সগুলি কীভাবে প্রয়োগ করে তার উপর নির্ভর করে তবে জিসিসির ক্ষেত্রে এই ধারণাটি যে কোনও রেফারেন্স কেবল স্ট্যাকের একটি পরিবর্তনশীলকে নির্দেশ করতে পারে আসলে সঠিক নয়, উদাহরণস্বরূপ এটি নিন:

#include <iostream>
int main(int argc, char** argv) {
    // Create a string on the heap
    std::string *str_ptr = new std::string("THIS IS A STRING");
    // Dereference the string on the heap, and assign it to the reference
    std::string &str_ref = *str_ptr;
    // Not even a compiler warning! At least with gcc
    // Now lets try to print it's value!
    std::cout << str_ref << std::endl;
    // It works! Now lets print and compare actual memory addresses
    std::cout << str_ptr << " : " << &str_ref << std::endl;
    // Exactly the same, now remember to free the memory on the heap
    delete str_ptr;
}

যার ফলে:

THIS IS A STRING
0xbb2070 : 0xbb2070

যদি আপনি খেয়াল করেন এমনকি মেমরিের ঠিকানাগুলিও ঠিক একইরকম হয়, যার অর্থ রেফারেন্সটি সাফল্যের সাথে হিপটিতে একটি পরিবর্তনশীলকে নির্দেশ করছে! এখন আপনি যদি সত্যিই অদ্ভুত হতে চান তবে এটিও কাজ করে:

int main(int argc, char** argv) {
    // In the actual new declaration let immediately de-reference and assign it to the reference
    std::string &str_ref = *(new std::string("THIS IS A STRING"));
    // Once again, it works! (at least in gcc)
    std::cout << str_ref;
    // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
    delete &str_ref;
    /*And, it works, because we are taking the memory address that the reference is
    storing, and deleting it, which is all a pointer is doing, just we have to specify
    the address with '&' whereas a pointer does that implicitly, this is sort of like
    calling delete &(*str_ptr); (which also compiles and runs fine).*/
}

যার ফলে:

THIS IS A STRING

সুতরাং একটি রেফারেন্স হুডের নীচে একটি পয়েন্টার, তারা দুজনেই কেবল একটি মেমরি ঠিকানা সঞ্চয় করে চলেছে, যেখানে ঠিকানাটি নির্দেশ করছে অপ্রাসঙ্গিক, আমি কী বলেছি যদি std :: cout << str_ref; কলিংয়ের পরে & str_ref মুছবেন? ঠিক আছে, স্পষ্টতই এটি সূক্ষ্ম সংকলন করে, তবে রানটাইমের সময় সেগমেন্টেশন ত্রুটি সৃষ্টি করে কারণ এটি আর বৈধ ভেরিয়েবলটির দিকে ইশারা করে না, আমাদের মূলত একটি ভাঙা রেফারেন্স রয়েছে যা এখনও বিদ্যমান (এটি সুযোগ থেকে বেরিয়ে আসা অবধি), কিন্তু অকেজো।

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

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

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

মনে রাখবেন, আমার উপরোক্ত উদাহরণগুলি কেবল এটিই, উদাহরণগুলি বোঝায় যে একটি রেফারেন্স কী, আপনি কখনই সেই উপায়ে কোনও রেফারেন্স ব্যবহার করতে চাইবেন না! একটি রেফারেন্সের সঠিক ব্যবহারের জন্য এখানে ইতিমধ্যে প্রচুর উত্তর রয়েছে যা মাথার পেরেকটি মারে


13

আরেকটি পার্থক্য হ'ল আপনার একটি শূন্য প্রকারের পয়েন্টার থাকতে পারে (এবং এর অর্থ কোনও কিছুর প্রতি নির্দেশক) তবে শূন্যতার উল্লেখগুলি নিষিদ্ধ।

int a;
void * p = &a; // ok
void & p = a;  //  forbidden

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


12

এছাড়াও, একটি সূত্র যা কোনও ফাংশনের প্যারামিটার যা ইনলাইন করা থাকে তা পয়েন্টারের চেয়ে আলাদাভাবে পরিচালনা করা যেতে পারে।

void increment(int *ptrint) { (*ptrint)++; }
void increment(int &refint) { refint++; }
void incptrtest()
{
    int testptr=0;
    increment(&testptr);
}
void increftest()
{
    int testref=0;
    increment(testref);
}

পয়েন্টার সংস্করণটি ইনলাইন করার সময় অনেক সংকলক প্রকৃতপক্ষে মেমোরিতে একটি লিখনকে বাধ্য করে (আমরা স্পষ্টভাবে ঠিকানাটি নিচ্ছি)। তবে তারা রেজিস্ট্রারে রেজিস্ট্রেশনটি ছেড়ে দেবে যা আরও অনুকূল।

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


10

উল্লেখগুলির আরেকটি আকর্ষণীয় ব্যবহার হ'ল কোনও ব্যবহারকারী-সংজ্ঞায়িত ধরণের ডিফল্ট যুক্তি সরবরাহ করা:

class UDT
{
public:
   UDT() : val_d(33) {};
   UDT(int val) : val_d(val) {};
   virtual ~UDT() {};
private:
   int val_d;
};

class UDT_Derived : public UDT
{
public:
   UDT_Derived() : UDT() {};
   virtual ~UDT_Derived() {};
};

class Behavior
{
public:
   Behavior(
      const UDT &udt = UDT()
   )  {};
};

int main()
{
   Behavior b; // take default

   UDT u(88);
   Behavior c(u);

   UDT_Derived ud;
   Behavior d(ud);

   return 1;
}

ডিফল্ট স্বাদ রেফারেন্সের 'অস্থায়ী থেকে বাইন্ড কনস্ট রেফারেন্স' ব্যবহার করে।


10

এই প্রোগ্রামটি প্রশ্নের উত্তর বুঝতে সাহায্য করতে পারে। এটি একটি রেফারেন্স "জে" এর একটি সাধারণ প্রোগ্রাম এবং একটি পয়েন্টার "পিটিআর" ভেরিয়েবল "এক্স" এর দিকে নির্দেশ করে।

#include<iostream>

using namespace std;

int main()
{
int *ptr=0, x=9; // pointer and variable declaration
ptr=&x; // pointer to variable "x"
int & j=x; // reference declaration; reference to variable "x"

cout << "x=" << x << endl;

cout << "&x=" << &x << endl;

cout << "j=" << j << endl;

cout << "&j=" << &j << endl;

cout << "*ptr=" << *ptr << endl;

cout << "ptr=" << ptr << endl;

cout << "&ptr=" << &ptr << endl;
    getch();
}

প্রোগ্রামটি চালান এবং আউটপুটটি একবার দেখুন এবং আপনি বুঝতে পারবেন।

এছাড়াও, 10 মিনিট অতিরিক্ত রাখুন এবং এই ভিডিওটি দেখুন: https://www.youtube.com/watch?v=rlJrrGV0iOg


10

আমার মনে হচ্ছে এখানে আরও একটি বিষয় রয়েছে যা এখানে coveredাকা হয়নি।

পয়েন্টারগুলির বিপরীতে, রেফারেন্সগুলি সিন্টেক্সটিকভাবে তারা যে বস্তুটি উল্লেখ করে তার সমতুল্য , অর্থাত্ কোনও বস্তু প্রয়োগ করা যেতে পারে এমন কোনও ক্রিয়াকলাপ একটি রেফারেন্সের জন্য কাজ করে, এবং ঠিক একই বাক্য গঠন সহ (ব্যতিক্রমটি অবশ্যই আরম্ভ হয়)।

যদিও এটি পর্যায়ে প্রদর্শিত হতে পারে, আমি বিশ্বাস করি যে এই সম্পত্তিটি বেশ কয়েকটি সি ++ বৈশিষ্ট্যের জন্য অত্যন্ত গুরুত্বপূর্ণ, উদাহরণস্বরূপ:

  • টেম্পলেট । যেহেতু টেম্পলেট প্যারামিটারগুলি হাঁস-টাইপযুক্ত, তাই কোনও প্রকারের সিনট্যাকটিক বৈশিষ্ট্যগুলি গুরুত্বপূর্ণ, তাই প্রায়শই একই টেমপ্লেট Tএবং উভয়ই ব্যবহার করা যেতে পারে T&
    (বা std::reference_wrapper<T>যা এখনও কোনও অন্তর্নিহিত কাস্টের উপর নির্ভর করে T&)
    টেম্পলেটগুলি যা উভয়ই কভার করে T&এবং T&&আরও সাধারণ।

  • লভ্যালুstr[0] = 'X';উল্লেখ ছাড়াই বিবৃতিটি বিবেচনা করুন এটি কেবল সি-স্ট্রিং ( char* str) এর জন্য কাজ করবে । রেফারেন্স দ্বারা চরিত্রটি ফিরিয়ে দেওয়া ব্যবহারকারী-সংজ্ঞায়িত শ্রেণিগুলিকে একই স্বরলিপি রাখতে দেয়।

  • অনুলিপি নির্মাণকারী । সিন্ট্যাক্টিক্যালি এটি কনস্ট্রাক্টরদের অনুলিপি করার জন্য বস্তুগুলি পাস করার জন্য অর্থবোধ করে, এবং অবজেক্টগুলিতে পয়েন্টার না করে। তবে কোনও অনুলিপি নির্মাণকারীর পক্ষে মান অনুসারে কোনও জিনিস তোলার কোনও উপায় নেই - এর ফলে একই অনুলিপি নির্মাণকারীকে পুনরাবৃত্ত কল আসতে পারে। এটি এখানে একমাত্র বিকল্প হিসাবে রেফারেন্স দেয়।

  • অপারেটর ওভারলোডস । রেফারেন্স সহ অপারেটর কলের সাথে ইন্ডিয়ারেশন পরিচয় করানো সম্ভব - operator+(const T& a, const T& b)একই ইনফিক্স নোটেশনটি ধরে রাখার সময় বলুন । এটি নিয়মিত ওভারলোডেড ফাংশনগুলির জন্যও কাজ করে।

এই পয়েন্টগুলি সি ++ এবং স্ট্যান্ডার্ড লাইব্রেরির একটি উল্লেখযোগ্য অংশকে ক্ষমতা দেয় যাতে এটি উল্লেখের বেশিরভাগ সম্পত্তি।


" অন্তর্নিহিত castালাই " castালাই একটি বাক্য গঠন যা এটি ব্যাকরণে বিদ্যমান; একটি কাস্ট সর্বদা সুস্পষ্ট
কৌতূহলী

9

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

void fn1(std::string s);
void fn2(const std::string& s);
void fn3(std::string& s);
void fn4(std::string* s);

void bar() {
    std::string x;
    fn1(x);  // Cannot modify x
    fn2(x);  // Cannot modify x (without const_cast)
    fn3(x);  // CAN modify x!
    fn4(&x); // Can modify x (but is obvious about it)
}

ফিরে ইন সি, এমন কল যা দেখে মনে হয় fn(x)কেবলমাত্র মান দ্বারা পাস করা যায়, তাই এটি অবশ্যই সংশোধন করতে পারে না x; যুক্তি সংশোধন করতে আপনাকে পয়েন্টারটি পাস করতে হবে fn(&x)। সুতরাং যদি কোনও যুক্তির আগে কোনও যুক্তি না আগে &আপনি জানতেন এটি সংশোধন করা হবে না। (কথোপকথন, &পরিবর্তিত অর্থ সত্য নয় কারণ আপনাকে কখনও কখনও constপয়েন্টার দ্বারা বড় পঠনযোগ্য কেবল কাঠামো পাস করতে হবে would )

কিছু যুক্তি দেখান যে কোড পড়ার সময় এটি এমন দরকারী বৈশিষ্ট্য, সেই পয়েন্টার প্যারামিটারগুলি সর্বদা অ-পরিবর্তিত পরিবর্তনের পরিবর্তিত পরামিতিগুলির জন্য ব্যবহার করা উচিতconst রেফারেন্সগুলির , এমনকি যদি ফাংশনটি কখনই প্রত্যাশা করে না nullptr। অর্থাত, এই লোকেরা যুক্তি দেয় যে fn3()উপরের মতো ফাংশন স্বাক্ষরগুলির অনুমতি দেওয়া উচিত নয়। গুগলের সি ++ স্টাইলের গাইডলাইনগুলি এর উদাহরণ।


8

সম্ভবত কিছু রূপক সাহায্য করবে; আপনার ডেস্কটপ স্ক্রিনস্পেসের প্রসঙ্গে -

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

6

পয়েন্টার এবং রেফারেন্সের মধ্যে পার্থক্য

একটি পয়েন্টার 0 এ আরম্ভ করা যেতে পারে এবং একটি রেফারেন্স নয়। আসলে, কোনও রেফারেন্স অবশ্যই কোনও অবজেক্টকে উল্লেখ করতে পারে তবে পয়েন্টারটি নাল পয়েন্টার হতে পারে:

int* p = 0;

কিন্তু আমরা থাকতে পারে না int& p = 0;এবং int& p=5 ;

এটি যথাযথভাবে করার জন্য, আমরা অবশ্যই প্রথমে কোনও বিষয় ঘোষিত ও সংজ্ঞায়িত করেছি অবশ্যই আমরা সেই বস্তুর একটি রেফারেন্স তৈরি করতে পারি, সুতরাং পূর্ববর্তী কোডটির সঠিক প্রয়োগটি হবে:

Int x = 0;
Int y = 5;
Int& p = x;
Int& p1 = y;

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

আরেকটি পার্থক্য হ'ল পয়েন্টারটি অন্য কোনও বস্তুতে নির্দেশ করতে পারে তবে রেফারেন্স সর্বদা একই বস্তুর প্রতি উল্লেখ থাকে, আসুন এই উদাহরণটি নেওয়া যাক:

Int a = 6, b = 5;
Int& rf = a;

Cout << rf << endl; // The result we will get is 6, because rf is referencing to the value of a.

rf = b;
cout << a << endl; // The result will be 5 because the value of b now will be stored into the address of a so the former value of a will be erased

আরেকটি বিষয়: যখন আমাদের কাছে কোনও এসটিএল টেম্পলেট জাতীয় টেম্পলেট থাকে তখন শ্রেণীর টেম্পলেট জাতীয় ধরণের টেম্পলেট সর্বদা একটি রেফারেন্স ফিরিয়ে দেয়, কোনও পয়েন্টার নয়, অপারেটরটি ব্যবহার করে সহজেই পড়া বা নতুন মান নির্ধারণের জন্য []:

Std ::vector<int>v(10); // Initialize a vector with 10 elements
V[5] = 5; // Writing the value 5 into the 6 element of our vector, so if the returned type of operator [] was a pointer and not a reference we should write this *v[5]=5, by making a reference we overwrite the element by using the assignment "="

1
আমরা এখনও পেতে পারি const int& i = 0
Revolver_Ocelot

1
এক্ষেত্রে রেফারেন্সটি কেবল পঠনে ব্যবহৃত হবে আমরা "কনস্ট_কাস্ট" ব্যবহার করেও এই কনট কনফারেন্সটি সংশোধন করতে পারি না কারণ "কনস্ট_কাস্ট" কেবলমাত্র পয়েন্টারটিকে রেফারেন্স হিসাবে গ্রহণ করে না।
dhokar.w

1
কনস্ট_কাস্ট খুব ভাল রেফারেন্সের সাথে কাজ করে: coliru.stacked-crooked.com/a/eebb454ab2cfd570
Revolver_Ocelot 16

1
আপনি রেফারেন্সের জন্য একটি কাস্ট তৈরি করছেন কোনও রেফারেন্স castালাই করছেন না; কনট ইনট & i =; const_cast <int- এ> (ঝ); আমি রেফারেন্সটির সম্ভাব্য লেখাকে লেখার জন্য এবং রেফারেন্সে নতুন মূল্য নির্ধারণের চেষ্টা করার চেষ্টা করি তবে এটি সম্ভব নয়। দয়া করে মনোযোগ দিন !!
dhokar.w

5

পার্থক্যটি হ'ল অ-ধ্রুবক পয়েন্টার ভেরিয়েবল (ধ্রুবককে পয়েন্টার দিয়ে বিভ্রান্ত করা উচিত নয়) প্রোগ্রাম সঞ্চালনের সময় কিছু সময় পরিবর্তিত হতে পারে, পয়েন্টার শব্দার্থক ব্যবহার করা প্রয়োজন (&, *) অপারেটরগুলি, যখন রেফারেন্স সূচনাতে সেট করা যেতে পারে কেবলমাত্র (এ কারণেই আপনি কেবল সেগুলি নির্মাণকারী আরম্ভকারী তালিকায় সেট করতে পারেন তবে অন্য কোনওভাবে নয়) এবং সাধারণ মান অ্যাক্সেস শব্দার্থক ব্যবহার করতে পারেন। মূলত রেফারেন্সগুলি অপারেটরদের ওভারলোডিংয়ের পক্ষে সহায়তা করার জন্য প্রবর্তন করা হয়েছিল যেহেতু আমি খুব প্রাচীন কিছু বইতে পড়েছি। যেহেতু কেউ এই থ্রেডে বলেছেন - পয়েন্টারটি 0 বা আপনি যে মানটি চান সেট করতে পারেন। 0 (NULL, nullptr) অর্থ পয়েন্টারটি কিছুই দিয়ে শুরু করা হয়নি। নাল পয়েন্টারকে অবজ্ঞা করার জন্য এটি একটি ত্রুটি। তবে আসলে পয়েন্টারে এমন কোনও মান থাকতে পারে যা কিছু সঠিক মেমোরি অবস্থানের দিকে নির্দেশ করে না। তাদের ঘুরিয়ে রেফারেন্সগুলি চেষ্টা করে যে কোনও ব্যবহারকারীর এমন কোনও রেফারেন্স সূচনা করার অনুমতি না দেয় যা আপনি সর্বদা সঠিক টাইপের মূল্যায়ন সরবরাহ করে এই কারণে যে উল্লেখ করা যায় না। যদিও রেফারেন্স ভেরিয়েবলকে ভুল মেমোরি অবস্থানের সূচনা করার জন্য অনেকগুলি উপায় রয়েছে - বিশদ বিবরণে এই গভীর খনন না করা আপনার পক্ষে ভাল। মেশিন স্তরে পয়েন্টার এবং রেফারেন্স উভয়ই সমানভাবে - পয়েন্টারগুলির মাধ্যমে কাজ করে। আসুন উল্লেখ করা যাক প্রয়োজনীয় উল্লেখগুলি সিনট্যাকটিক চিনি। মূল্যের উল্লেখগুলি এর থেকে আলাদা - এগুলি প্রাকৃতিকভাবে স্ট্যাক / হ্যাপ অবজেক্ট। যদিও রেফারেন্স ভেরিয়েবলকে ভুল মেমোরি অবস্থানের সূচনা করার জন্য অনেকগুলি উপায় রয়েছে - বিশদ বিবরণে এই গভীর খনন না করা আপনার পক্ষে ভাল। মেশিন স্তরে পয়েন্টার এবং রেফারেন্স উভয়ই সমানভাবে - পয়েন্টারগুলির মাধ্যমে কাজ করে। আসুন উল্লেখ করা যাক প্রয়োজনীয় উল্লেখগুলি সিনট্যাকটিক চিনি। মূল্যের উল্লেখগুলি এর থেকে আলাদা - এগুলি প্রাকৃতিকভাবে স্ট্যাক / হ্যাপ অবজেক্ট। যদিও রেফারেন্স ভেরিয়েবলকে ভুল মেমোরি অবস্থানের সূচনা করার জন্য অনেকগুলি উপায় রয়েছে - বিশদ বিবরণে এই গভীর খনন না করা আপনার পক্ষে ভাল। মেশিন স্তরে পয়েন্টার এবং রেফারেন্স উভয়ই সমানভাবে - পয়েন্টারগুলির মাধ্যমে কাজ করে। আসুন উল্লেখ করা যাক প্রয়োজনীয় উল্লেখগুলি সিনট্যাকটিক চিনি। মূল্যের উল্লেখগুলি এর থেকে আলাদা - এগুলি প্রাকৃতিকভাবে স্ট্যাক / হ্যাপ অবজেক্ট।


4

সহজ কথায়, আমরা বলতে পারি একটি রেফারেন্স একটি ভেরিয়েবলের বিকল্প নাম যেখানে পয়েন্টার একটি ভেরিয়েবল যা অন্য ভেরিয়েবলের ঠিকানা ধারণ করে। যেমন

int a = 20;
int &r = a;
r = 40;  /* now the value of a is changed to 40 */

int b =20;
int *ptr;
ptr = &b;  /*assigns address of b to ptr not the value */
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.