একটি সি ++ রেফারেন্স পরিবর্তনশীল মন্দ কি ফিরে আসার অভ্যাস?


341

এটাকে আমি একটু সাবজেক্টিভ মনে করি; আমি মতামতটি সর্বসম্মত হবে কিনা তা নিশ্চিত নই (আমি প্রচুর কোড স্নিপেট দেখেছি যেখানে রেফারেন্সগুলি ফিরে আসে)।

এই প্রশ্নটির দিকে আমি কেবল জিজ্ঞাসা করেছি, রেফারেন্স সূচনা করার বিষয়ে , একটি রেফারেন্স ফিরে দেওয়া খারাপ হতে পারে কারণ, [যেমন আমি বুঝতে পেরেছি] এটি মুছে ফেলা সহজ করে তোলে যা স্মৃতি ফাঁস হতে পারে।

এটি আমাকে চিন্তিত করে, যেমন আমি উদাহরণগুলি অনুসরণ করেছি (যদি না আমি বিষয়গুলি কল্পনা করি) এবং বেশ কয়েকটি জায়গায় এটি করেছি ... আমি কি ভুল বুঝেছি? এটা কি মন্দ? যদি তাই হয়, ঠিক কত খারাপ?

আমি অনুভব করি যে আমার পয়েন্টার এবং রেফারেন্সগুলির মিশ্র ব্যাগের কারণে, আমি সি ++ তে নতুন আছি এবং কখন কী ব্যবহার করব সে সম্পর্কে সম্পূর্ণ বিভ্রান্তি, আমার অ্যাপ্লিকেশনগুলি অবশ্যই মেমরি ফুটো নরক হতে পারে ...

এছাড়াও, আমি বুঝতে পারি যে স্মার্ট / শেয়ার্ড পয়েন্টার ব্যবহার সাধারণত মেমরি ফাঁস এড়ানোর সর্বোত্তম উপায় হিসাবে গ্রহণ করা হয়।


আপনি গেটের মতো ফাংশন / পদ্ধতি লিখতে থাকলে মন্দ নয়।
জন জেড লি লি

উত্তর:


411

সাধারণভাবে, কোনও রেফারেন্স ফিরিয়ে দেওয়া পুরোপুরি স্বাভাবিক এবং সর্বদা ঘটে।

আপনি যদি বলতে চান:

int& getInt() {
    int i;
    return i;  // DON'T DO THIS.
}

এটাই সব ধরণের মন্দ। স্ট্যাক বরাদ্দ iচলে যাবে এবং আপনি কিছুই উল্লেখ করছেন। এটি মন্দও:

int& getInt() {
    int* i = new int;
    return *i;  // DON'T DO THIS.
}

কারণ এখন ক্লায়েন্টকে শেষ পর্যন্ত অদ্ভুত কাজটি করতে হবে:

int& myInt = getInt(); // note the &, we cannot lose this reference!
delete &myInt;         // must delete...totally weird and  evil

int oops = getInt(); 
delete &oops; // undefined behavior, we're wrongly deleting a copy, not the original

নোট করুন যে মূল্যবোধের রেফারেন্সগুলি এখনও কেবলমাত্র রেফারেন্স, তাই সমস্ত মন্দ অ্যাপ্লিকেশন একই থাকে।

আপনি যদি এমন কিছু বরাদ্দ করতে চান যা ফাংশনের আওতার বাইরে চলে যায় তবে একটি স্মার্ট পয়েন্টার (বা সাধারণভাবে, একটি ধারক) ব্যবহার করুন:

std::unique_ptr<int> getInt() {
    return std::make_unique<int>(0);
}

এবং এখন ক্লায়েন্ট একটি স্মার্ট পয়েন্টার সঞ্চয় করে:

std::unique_ptr<int> x = getInt();

আপনি যে জীবনকালে জানেন উচ্চতর স্তরের উপর উন্মুক্ত রাখা হচ্ছে এমন জিনিসগুলিতে অ্যাক্সেসের জন্য উল্লেখগুলিও ঠিক আছে, যেমন:

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

এখানে আমরা জানি যে একটি রেফারেন্স ফিরিয়ে দেওয়া ঠিক আছে i_কারণ আমাদের যা কিছু ডাকছে তা শ্রেণীর উদাহরণের জীবনকাল পরিচালনা করে, তাই i_কমপক্ষে দীর্ঘকাল বেঁচে থাকবে।

এবং অবশ্যই, ঠিক আছে:

int getInt() {
   return 0;
}

যদি আজীবন কলার ছেড়ে দেওয়া উচিত, এবং আপনি কেবল মানটি গণনা করছেন।

সংক্ষিপ্তসার: কলটির পরে যদি অবজেক্টটির জীবনকাল শেষ না হয় তবে কোনও রেফারেন্স ফিরিয়ে দেওয়া ঠিক আছে।


21
এগুলি সব খারাপ উদাহরণ। যথাযথ ব্যবহার উল্লেখযোগ্য উদাহরণ হচ্ছে যখন আপনি একটি বস্তু যে পাস হয় একটি রেফারেন্স ফিরে আসছে Ala অপারেটর <<।
Arelius

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

12
স্বাক্ষরকারীদের সম্পাদনা করুন: আপনি যদি এর যথার্থতার জন্য প্রমাণ দিতে না পারেন তবে সম্পাদনাগুলি অনুমোদিত করবেন না। আমি ভুল সম্পাদনাটি রোলব্যাক করেছি।
GManNickG

7
উত্তরোত্তরদের জন্য, এবং এটির জন্য যে কোনও নতুন প্রোগ্রামাররা তাড়ানোর জন্য লিখবেন নাreturn new int
অরবিট

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

64

না, না, হাজার বার নয়।

যা খারাপ তা হ'ল গতিশীলভাবে বরাদ্দ হওয়া বস্তুর একটি রেফারেন্স তৈরি করা এবং মূল পয়েন্টারটি হারাতে। আপনি যখন newকোনও বিষয় যখন গ্যারান্টিযুক্ত একটি বাধ্যবাধকতা গ্রহণ delete

তবে একবার দেখুন, উদাহরণস্বরূপ operator<<: এটি অবশ্যই একটি রেফারেন্স, বা return

cout << "foo" << "bar" << "bletch" << endl ;

কাজ করবে না


23
আমি হ্রাস পেয়েছি কারণ এটির কোনও প্রশ্নেরই উত্তর নেই (যেখানে ওপি স্পষ্ট করে দিয়েছে যে সে মুছে ফেলার প্রয়োজনীয়তা জানে) বা বৈধ ভয়কেও সম্বোধন করে না যে কোনও ফ্রিস্টোর অবজেক্টের রেফারেন্স ফিরিয়ে দেওয়া বিভ্রান্তির কারণ হতে পারে। দীর্ঘশ্বাস.

4
কোনও রেফারেন্স অবজেক্ট ফেরত দেওয়ার অভ্যাসটি মন্দ নয় । এরো নং। তিনি যে ভয়টি প্রকাশ করেছেন তা হ'ল সঠিক ভয়, যেমনটি আমি দ্বিতীয় গ্রাফের দিকে তুলে ধরেছি।
চার্লি মার্টিন

আপনি আসলে না। তবে এটি আমার সময়ের জন্য উপযুক্ত নয়।

2
ইরাইমিলঞ্জ @ "" না "সম্পর্কে - আমি যত্ন করি না। তবে এই পোস্টটি একটি গুরুত্বপূর্ণ তথ্য নির্দেশ করেছে যা GMan থেকে অনুপস্থিত ছিল।
Kobor42

48

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

কোনও স্থানীয় ভেরিয়েবল বা এ জাতীয় কিছুতে কোনও রেফারেন্স কখনই ফিরিয়ে আনবেন না, কারণ এটি রেফারেন্স করার মতো হবে না।

আপনি ফাংশনটির থেকে পৃথক কোনও কিছুর একটি রেফারেন্স ফিরিয়ে দিতে পারেন, যা কলিং ফাংশনটি মোছার জন্য দায়িত্ব নেবে বলে আপনি আশা করেন না। এটি আদর্শ operator[]ফাংশনের ক্ষেত্রে ।

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


1
দুর্দান্ত উত্তর তবে "আপনি কনস্ট্যান্ড রেফারেন্স হিসাবে একটি অস্থায়ী ফিরিয়ে দিতে পারেন।" নিম্নলিখিত কোডটি সংকলন করবে তবে সম্ভবত ক্রাশ হবে কারণ প্রত্যাবর্তনের বিবৃতি শেষে অস্থায়ী ধ্বংস হয়ে গেছে: "ইনট কনস্টান্ট & এফ () {রিটার্ন 42;} শূন্যস্থানীয় মূল () {ইন্ট কনস্ট & আর = ফ (); ++ আর;} "
j_random_hacker

@ জেআর্যান্ডম_হ্যাকার: অস্থায়ীদের জন্য রেফারেন্সের জন্য সি ++ এর কিছু অদ্ভুত নিয়ম রয়েছে, যেখানে অস্থায়ী জীবনকাল বাড়ানো যেতে পারে। আমি দুঃখিত আমি এটি আপনার কেসটি কভার করে কিনা তা জানার জন্য এটি যথেষ্টভাবে বুঝতে পারি না।
মার্ক রান্সম

3
@ মার্ক: হ্যাঁ, এর কিছু অদ্ভুত নিয়ম আছে। একটি অস্থায়ী জীবনকাল কেবলমাত্র একটি কনস্টের রেফারেন্স (এটি কোনও শ্রেণীর সদস্য নয়) এর সাথে শুরু করে বাড়ানো যেতে পারে; এটি তখন পর্যন্ত বেঁচে থাকে যতক্ষণ না রেফ স্কোপের বাইরে চলে যায়। দুঃখের বিষয়, কনস্টের রেফ ফিরিয়ে দেওয়া কভার নয় । মান অনুসারে কোনও টেম্পার ফিরিয়ে দেওয়া নিরাপদ।
j_random_hacker

সি ++ স্ট্যান্ডার্ড, 12.2 দেখ, অনুচ্ছেদ 5. এছাড়াও সপ্তাহের ঔষধি Sutter এর বিপথগামী গুরু দেখতে herbsutter.wordpress.com/2008/01/01/...
ডেভিড থর্নলি

4
@ ডেভিড: ফাংশনটির রিটার্ন টাইপ যখন "টি কনস্ট্যান্ড" হয়, তখন প্রকৃতপক্ষে কী ঘটে তা হ'ল রিটার্নের স্টেটমেন্টটি স্পষ্টভাবে টেম্পকে রূপান্তর করে যা টি টাইপ করে, T..6.৩.২ অনুসারে "টি কনস্ট্যান্ড" টাইপ করতে (একটি আইনী রূপান্তর তবে একটি যা আজীবন প্রসারিত হয় না), এবং তারপরে কলিং কোডটি ফাংশনের ফলাফলের সাথে "টি কনস্ট &" টাইপের রেফারিকে আরম্ভ করে, আবার "টি কনস্ট্যান্ড" টাইপ করুন - আবারও, একটি আইনী তবে আজীবন প্রসারিত প্রক্রিয়া। শেষ ফলাফল: আজীবন কোনও এক্সটেনশন এবং অনেক বিভ্রান্তি। :(
j_random_hacker

26

উত্তরগুলি সন্তোষজনক নয় বলে আমি আমার দুটি সেন্ট যুক্ত করব।

আসুন নিম্নলিখিত বিষয়গুলি বিশ্লেষণ করুন:

ভ্রান্ত ব্যবহার

int& getInt()
{
    int x = 4;
    return x;
}

এটি স্পষ্টতই ত্রুটি

int& x = getInt(); // will refer to garbage

স্ট্যাটিক ভেরিয়েবলের ব্যবহার

int& getInt()
{
   static int x = 4;
   return x;
}

এটি ঠিক, কারণ স্থির ভেরিয়েবলগুলি কোনও প্রোগ্রামের আজীবন কার্যকর থাকে।

int& x = getInt(); // valid reference, x = 4

সিঙ্গলটন প্যাটার্ন প্রয়োগ করার সময় এটিও বেশ সাধারণ

Class Singleton
{
    public:
        static Singleton& instance()
        {
            static Singleton instance;
            return instance;
        };

        void printHello()
        {
             printf("Hello");
        };

}

ব্যবহার:

 Singleton& my_sing = Singleton::instance(); // Valid Singleton instance
 my_sing.printHello();  // "Hello"

অপারেটর

আদর্শ পাঠাগার পাত্রে অপারেটরগুলির ব্যবহারের উপর নির্ভর করে যা রেফারেন্স দেয়

T & operator*();

নিম্নলিখিত ব্যবহার করা যেতে পারে

std::vector<int> x = {1, 2, 3}; // create vector with 3 elements
std::vector<int>::iterator iter = x.begin(); // iterator points to first element (1)
*iter = 2; // modify first element, x = {2, 2, 3} now

অভ্যন্তরীণ ডেটাতে দ্রুত অ্যাক্সেস

এমন সময় আছে যখন & অভ্যন্তরীণ ডেটাতে অ্যাক্সেসের জন্য ব্যবহার করা যেতে পারে

Class Container
{
    private:
        std::vector<int> m_data;

    public:
        std::vector<int>& data()
        {
             return m_data;
        }
}

ব্যবহারের সাথে:

Container cont;
cont.data().push_back(1); // appends element to std::vector<int>
cont.data()[0] // 1

যাইহোক, এটি এর মতো অসুবিধায় পড়তে পারে:

Container* cont = new Container;
std::vector<int>& cont_data = cont->data();
cont_data.push_back(1);
delete cont; // This is bad, because we still have a dangling reference to its internal data!
cont_data[0]; // dangling reference!

স্ট্যাটিক ভেরিয়েবলের রেফারেন্স ফিরিয়ে দেওয়া trueIf((a*b) == (c*d))
অনাকাঙ্ক্ষিত

Container::data()এর বাস্তবায়নটি পড়তে হবেreturn m_data;
Xeaz

এটি খুব সহায়ক ছিল, ধন্যবাদ! @ শিয়েজ এ্যাপেন্ড কল নিয়ে কি সমস্যা সৃষ্টি করবে না?
অ্যান্ড্রু

@ সেবতু আপনি কেন এমনটি করতে চান?
thorhunter

@ এন্ড্রু না, এটি একটি সিনট্যাক্স শেনানিগান ছিল। আপনি যদি উদাহরণস্বরূপ কোনও পয়েন্টার প্রকারটি ফেরত পাঠিয়ে থাকেন তবে আপনি একটি পয়েন্টার তৈরি এবং ফিরে দেওয়ার জন্য রেফারেন্স ঠিকানাটি ব্যবহার করবেন।
thorhunter

14

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

এটি দিয়ে অর্জন করা যায় এমন ভাল জিনিস রয়েছে (যেমন মানচিত্র [নাম] = "হ্যালো ওয়ার্ল্ড")


1
আমি শুধু কৌতূহলী, কি সম্পর্কে ভাল map[name] = "hello world"?
ভুল ব্যবহারকারী নাম

5
@ র্রংগুজারনাম সিনট্যাক্সটি স্বজ্ঞাত। HashMap<String,Integer>জাভাতে সঞ্চিত কোনও মান গণনা বাড়ানোর চেষ্টা করেছেন কখনও ? : পি
মেহরদাদ আফশারী

হাহাহা, এখনও নয়, তবে হাশম্যাপের উদাহরণগুলির দিকে তাকালে এটি বেশ
জাঁকজমকপূর্ণ দেখাচ্ছে

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

10

"রেফারেন্স ফিরিয়ে দেওয়া খারাপ কারণ, কেবল [যেমন আমি বুঝতে পেরেছি] এটি মুছে ফেলা সহজ করে তোলে"

সত্য না. কোনও রেফারেন্স ফিরিয়ে দেওয়া মালিকানার শব্দার্থ বোঝায় না। এটি কেবলমাত্র আপনি এটি করার কারণে:

Value& v = thing->getTheValue();

... এর অর্থ এই নয় যে আপনি এখন v দ্বারা উল্লিখিত স্মৃতিটির মালিক হন;

তবে এটি ভয়াবহ কোড:

int& getTheValue()
{
   return *new int;
}

যদি আপনি এটির মতো কিছু করছেন কারণ "আপনার যদি সেই উদাহরণে কোনও পয়েন্টার প্রয়োজন হয় না" তবে: ১) আপনার যদি কোনও রেফারেন্সের প্রয়োজন হয় তবে পয়েন্টারটিকে কেবলমাত্র ডিফারেন্স করুন এবং ২) আপনার শেষ পর্যন্ত পয়েন্টারের প্রয়োজন হবে, কারণ আপনাকে একটি ম্যাচ করতে হবে মুছে ফেলা সহ নতুন এবং আপনার কল মুছার জন্য একটি পয়েন্টার দরকার।


7

দুটি মামলা রয়েছে:

  • কনস্ট্রাক্ট রেফারেন্স - ভাল ধারণা, কখনও কখনও বিশেষত ভারী বস্তু বা প্রক্সি ক্লাসগুলির জন্য, সংকলক অনুকূলিতকরণ

  • নন-কনস্ট্যান্ট রেফারেন্স --বাদ ধারণা, কখনও কখনও, এনক্যাপসুলেশনের বিরতি দেয়

উভয়ই একই সমস্যা ভাগ করে নেবে - সম্ভাব্যভাবে ধ্বংস হওয়া বস্তুর দিকে ইঙ্গিত করতে পারে ...

আমি আপনাকে এমন অনেক পরিস্থিতিতে স্মার্ট পয়েন্টার ব্যবহার করার পরামর্শ দিচ্ছি যেখানে আপনাকে কোনও রেফারেন্স / পয়েন্টার ফিরিয়ে দিতে হবে।

এছাড়াও, নিম্নলিখিত নোট:

একটি আনুষ্ঠানিক নিয়ম রয়েছে - সি ++ স্ট্যান্ডার্ড (বিভাগ আপনি যদি আগ্রহী হন 13.3.3.1.4) উল্লেখ করে যে একটি অস্থায়ী কেবল একটি কনস্টের রেফারেন্সের সাথে আবদ্ধ হতে পারে - আপনি যদি কোনও অ-কনস্ট্যান্ট রেফারেন্স ব্যবহার করার চেষ্টা করেন তবে সংকলককে অবশ্যই এটি পতাকাঙ্কিত করতে হবে একটি ভুল.


1
অ-কনস্ট্যান্ট রেফ অগত্যা এনক্যাপসুলেশনটি ভেঙে দেয়। ভেক্টর বিবেচনা করুন :: অপারেটর []

এটি একটি বিশেষ ঘটনা ... তাই আমি মাঝে মাঝে বলেছিলাম, যদিও আমার সত্যিকারের সবচেয়ে বেশি সময় দাবি করা উচিত :)

সুতরাং, আপনি বলছেন যে সাধারণ সাবস্ক্রিপ্ট অপারেটর বাস্তবায়ন একটি প্রয়োজনীয় মন্দ? আমি এর সাথেও একমত বা একমত নই; আমি যেমন বুদ্ধিমান কেউ না।
নিক বোল্টন

আমি এটি বলছি না, তবে এটি ব্যবহার করা খারাপ হতে পারে :))) ভেক্টর :: যখনই সম্ভব সম্ভব ব্যবহার করা উচিত ....

অঁ্যা? ভেক্টর :: এছাড়াও একটি ননকনস্ট রেফারেন্স প্রদান করে।

4

এটি কেবল মন্দ নয়, এটি কখনও কখনও প্রয়োজনীয়ও হয়। উদাহরণস্বরূপ, রেফারেন্স রিটার্ন মান ব্যবহার না করে std :: ভেক্টরের [] অপারেটরটি প্রয়োগ করা অসম্ভব।


আহ, হ্যাঁ অবশ্যই; আমি মনে করি এই কারণেই আমি এটি ব্যবহার শুরু করেছি; আমি যখন সাবস্ক্রিপ্ট অপারেটরটি প্রথম প্রয়োগ করলাম তখনই আমি উল্লেখগুলির ব্যবহার বুঝতে পেরেছিলাম। আমি বিশ্বাস করতে নেতৃত্ব দিচ্ছি যে এটিই বাস্তব বিষয়।
নিক বোল্টন

অদ্ভুতভাবে যথেষ্ট, আপনি operator[]কোনও রেফারেন্স ব্যবহার না করেই ধারকটির জন্য প্রয়োগ করতে পারেন ... এবং std::vector<bool>করেন। (এবং প্রক্রিয়াটিতে একটি বাস্তব জগাখিচুড়ি সৃষ্টি করে)
বেন ভয়েগট

@ বেনভয়েগ এমএমএম, কেন গোলমাল? প্রক্সি ফিরে আসা জটিল স্টোরেজযুক্ত পাত্রে বৈধ দৃশ্যাবলী যা বাইরের ধরণের (যেমন ::std::vector<bool>আপনি উল্লেখ করেছেন) সরাসরি ম্যাপ করে না ।
সের্গে.ইউকোসোটিক্যাক্সিস.আইভানভ

1
@ Sergey.quixoticaxis.Ivanov: জগাখিচুড়ি যে ব্যবহার করছে std::vector<T>টেমপ্লেট কোডে, নষ্ট হয়ে গেছে যদি Tহতে পারে bool, কারণ std::vector<bool>অন্যান্য instantiations থেকে ভিন্ন আচরণ আছে। এটি দরকারী, তবে এটির নিজস্ব নাম দেওয়া উচিত ছিল না বিশেষায়িত std::vector
বেন ভয়েগট

@ বেনওয়েট আমি একটি বিশেষীকরণকে "সত্যই বিশেষ" করার অদ্ভুত সিদ্ধান্তের বিষয়ে একমত পোষণ করি তবে আমি অনুভব করেছি যে আপনার মূল মন্তব্যটি থেকেই বোঝা যাচ্ছে যে প্রক্সি ফিরিয়ে দেওয়া সাধারণভাবে অদ্ভুত।
সের্গেই.কুইক্সোটিক্যাক্সিস.আইভানভ

2

গৃহীত উত্তরের সাথে যোগ করুন:

struct immutableint {
    immutableint(int i) : i_(i) {}

    const int& get() const { return i_; }
private:
    int i_;
};

আমি যুক্তি দেব যে এই উদাহরণটি ঠিক নয় এবং সম্ভব হলে এড়ানো উচিত। কেন? ঝুঁকির রেফারেন্স সহ শেষ হওয়া খুব সহজ ।

উদাহরণটির সাথে পয়েন্টটি বর্ণনা করার জন্য:

struct Foo
{
    Foo(int i = 42) : boo_(i) {}
    immutableint boo()
    {
        return boo_;
    }  
private:
    immutableint boo_;
};

বিপদ-অঞ্চলে প্রবেশ করা:

Foo foo;
const int& dangling = foo.boo().get(); // dangling reference!

1

রিটার্ন রেফারেন্সটি সাধারণত বড় অবজেক্টের জন্য সি ++ এ অপারেটর ওভারলোডিংয়ে ব্যবহৃত হয়, কারণ একটি মান ফিরিয়ে দেওয়ার জন্য অনুলিপি অপারেশন প্রয়োজন (

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

আপনি যদি রিটার্নিং রেফারেন্স ব্যবহার করতে চান তবে আপনি স্ট্যাটিক অবজেক্টের বাফার ব্যবহার করতে পারেন। উদাহরণ স্বরূপ

const max_tmp=5; 
Obj& get_tmp()
{
 static int buf=0;
 static Obj Buf[max_tmp];
  if(buf==max_tmp) buf=0;
  return Buf[buf++];
}
Obj& operator+(const Obj& o1, const Obj& o1)
{
 Obj& res=get_tmp();
 // +operation
  return res;
 }

এইভাবে, আপনি নিরাপদে ফিরে আসা রেফারেন্স ব্যবহার করতে পারেন।

তবে আপনি সর্বদা ফাংশনে মান ফেরত দেওয়ার জন্য রেফারেন্সের পরিবর্তে পয়েন্টার ব্যবহার করতে পারেন।


0

আমি মনে করি ফাংশনের রিটার্ন মান হিসাবে রেফারেন্স ব্যবহার করা ফাংশনের রিটার্ন মান হিসাবে পয়েন্টার ব্যবহার করার চেয়ে অনেক বেশি সোজা এগিয়ে। দ্বিতীয়ত স্থিতিশীল ভেরিয়েবলটি ব্যবহার করা সর্বদা নিরাপদ হবে যেখানে প্রত্যাবর্তনের মান উল্লেখ করা হয়।


0

সর্বোত্তম জিনিস হ'ল অবজেক্ট তৈরি করা এবং এটিকে কোনও ক্রিয়ায় রেফারেন্স / পয়েন্টার পরামিতি হিসাবে সরবরাহ করা যা এই ভেরিয়েবলটি বরাদ্দ করে।

ফাংশন অবজেক্টের বরাদ্দকরণ এবং রেফারেন্স বা পয়েন্টার হিসাবে এটিকে ফিরিয়ে দেওয়া (পয়েন্টারটি তবে নিরাপদ) ফাংশন ব্লকের শেষে মেমরি মুক্ত করার কারণে এটি খারাপ ধারণা।


-1
    Class Set {
    int *ptr;
    int size;

    public: 
    Set(){
     size =0;
         }

     Set(int size) {
      this->size = size;
      ptr = new int [size];
     }

    int& getPtr(int i) {
     return ptr[i];  // bad practice 
     }
  };

getPtr ফাংশন মোছার পরে বা এমনকি কোনও নাল বস্তুর পরে গতিশীল মেমরি অ্যাক্সেস করতে পারে। যা খারাপ অ্যাক্সেস ব্যতিক্রমগুলির কারণ হতে পারে। পরিবর্তে গেটর এবং সেটার বাস্তবায়ন করা উচিত এবং ফেরার আগে আকার যাচাই করা উচিত।


-2

লভ্যালু হিসাবে কাজ (ওরফে, নন-কনস্ট্যান্ট রেফারেন্সগুলি ফিরিয়ে দেওয়া) সি ++ থেকে সরানো উচিত। এটি মারাত্মকভাবে অনিশ্চিত। স্কট মায়ার্স এই আচরণ সহ একটি মিনিট () চেয়েছিলেন।

min(a,b) = 0;  // What???

যা আসলে উন্নতি হয় না

setmin (a, b, 0);

দ্বিতীয়টি আরও বেশি অর্থবোধ করে।

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


2
নিশ্চিত যে এটি বিপজ্জনক, এবং আরও ভাল সংকলক ত্রুটি পরীক্ষা করা উচিত, তবে এটি ব্যতীত কিছু দরকারী নির্মাণ করা যায়নি, যেমন স্ট্যান্ড :: মানচিত্রে অপারেটর [] ()।
j_random_hacker

2
অবিচ্ছিন্ন উল্লেখগুলি ফিরিয়ে দেওয়া আসলে অবিশ্বাস্যভাবে কার্যকর useful vector::operator[]উদাহরণ স্বরূপ. আপনি বরং লিখবেন v.setAt(i, x)নাকি v[i] = x? পরেরটি সুদূর উচ্চতর।
মাইলস রাউট

1
@ মাইলসআউট আমি যে v.setAt(i, x)কোনও সময় যাব । এটি সুদূর উচ্চতর।
স্ক্র্যাভি

-2

আমি একটি বাস্তব সমস্যার মধ্যে দৌড়েছি যেখানে এটি সত্যই খারাপ ছিল। মূলত কোনও বিকাশকারী কোনও ভেক্টরের কোনও অবজেক্টের রেফারেন্স ফিরিয়ে দেন। ওটা খারাপ ছিল!!!

জানুয়ারীতে আমি যে সমস্ত বিবরণ লিখেছি তা: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html


2
কলিং কোডে যদি আপনার মূল মানটি পরিবর্তন করতে হয় তবে আপনাকে অবশ্যই একটি রেফ ফিরিয়ে দিতে হবে। এবং এটি প্রকৃতপক্ষে কোনও পুনরুদ্ধারকারীকে একজন ভেক্টরে ফেরত দেওয়ার চেয়ে আর বিপজ্জনক নয় - যদি উপাদানগুলিকে ভেক্টরটিতে যুক্ত করা হয় বা সরিয়ে দেওয়া হয় তবে উভয়ই বাতিল হয়ে যায়।
j_random_hacker

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

-15

ভয়াবহ কোড সম্পর্কে:

int& getTheValue()
{
   return *new int;
}

সুতরাং, প্রকৃতপক্ষে, মেমরি পয়েন্টারটি ফিরে যাওয়ার পরে হারিয়ে গেছে। তবে আপনি যদি এইভাবে ভাগ করা_পিটার ব্যবহার করেন:

int& getTheValue()
{
   std::shared_ptr<int> p(new int);
   return *p->get();
}

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


12
এটি হারিয়ে গেছে কারণ ভাগ করা পয়েন্টারটি সুযোগের বাইরে চলে যায় এবং পূর্ণসংখ্যাকে মুক্ত করে।

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