কোনও অ-স্থির রেফারেন্স কীভাবে অস্থায়ী বস্তুর সাথে আবদ্ধ হতে পারে না?


226

কোনও অস্থায়ী বস্তুর নন-কনস্ট্যান্ট রেফারেন্স কেন দেওয়া হচ্ছে না, কোন ফাংশনটি getx()ফেরত দেয়? স্পষ্টত, এই সি ++ স্ট্যান্ডার্ড দ্বারা নিষিদ্ধ করা হয় কিন্তু আমি যেমন সীমাবদ্ধতা উদ্দেশ্য আগ্রহী না একটি রেফারেন্স মান।

struct X
{
    X& ref() { return *this; }
};

X getx() { return X();}

void g(X & x) {}    

int f()
{
    const X& x = getx(); // OK
    X& x = getx(); // error
    X& x = getx().ref(); // OK
    g(getx()); //error
    g(getx().ref()); //OK
    return 0;
}
  1. এটা পরিষ্কার যে অবজেক্টের আজীবন কারণ হতে পারে না কারণ কোনও বস্তুর নিয়মিত রেফারেন্স সি ++ স্ট্যান্ডার্ড দ্বারা নিষিদ্ধ নয়
  2. এটি স্পষ্ট যে অস্থায়ী বস্তু উপরের নমুনায় ধ্রুবক নয়, কারণ অ ধ্রুবক ফাংশনগুলিতে কল করার অনুমতি রয়েছে। উদাহরণস্বরূপ, ref()অস্থায়ী বস্তুটি সংশোধন করতে পারে।
  3. তদতিরিক্ত, ref()আপনাকে সংকলককে বোকা বানাতে এবং এই অস্থায়ী বস্তুর লিঙ্ক পেতে দেয় এবং এটি আমাদের সমস্যা সমাধান করে।

এছাড়াও:

তারা বলেছে "কনস্টের্ট রেফারেন্সটিতে একটি অস্থায়ী অবজেক্ট বরাদ্দ করা এই বস্তুর আজীবন প্রসারিত করে" এবং "যদিও নন-কনস্ট্যান্ট রেফারেন্স সম্পর্কে কিছুই বলা হয় না"। আমার অতিরিক্ত প্রশ্ন । নিম্নলিখিত অ্যাসাইনমেন্টটি অস্থায়ী বস্তুর আজীবন প্রসারিত করে?

X& x = getx().ref(); // OK

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

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

2
প্রাপ্ত নম্বর # 88: "সর্বাধিক গুরুত্বপূর্ণ কনস্ট" এর প্রার্থী " herbsutter.spaces.live.com/blog/cns !
2D4327CC297151BB!

4
@ মিশেল: ভিসি নন-কনস্ট্যান্ট রেফারেন্সগুলিকে মূল্যায়ন বাঁধেন। তারা এটিকে একটি বৈশিষ্ট্য বলে, কিন্তু সত্যই এটি একটি বাগ। (দ্রষ্টব্য যে এটি কোনও বাগ নয় কারণ এটি অন্তর্নিহিতভাবে অযৌক্তিক নয়, তবে নির্বোধ ত্রুটিগুলি রোধ করার জন্য এটি স্পষ্টভাবে বাতিল করা হয়েছিল।)
এসবিআই

উত্তর:


97

মূলসূত্র উল্লেখ সম্পর্কে এই ভিজ্যুয়াল সি ++ ব্লগ নিবন্ধ থেকে :

... সি ++ চান না যে আপনি দুর্ঘটনাক্রমে অস্থায়ী সংস্থাগুলি সংশোধন করতে পারেন, তবে পরিবর্তিত মূল্যবোধে অ-কনস্ট্যান্ট সদস্য ফাংশনটি সরাসরি কল করা সুস্পষ্ট, সুতরাং এটি অনুমোদিত ...

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

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

ভাষার বিরুদ্ধে গিয়ে সংকলককে বোকা বানানো খুব কমই সমস্যা সমাধান করে - সাধারণত এটি সমস্যা তৈরি করে।


সম্পাদনা করুন: মন্তব্যে প্রশ্নগুলিতে সম্বোধন করা: 1) X& x = getx().ref(); // OK when will x die?- আমি জানি না এবং আমি যত্নও করি না, কারণ "ভাষার বিরুদ্ধে যাওয়া" বলতে আমি এটাই বুঝি। ভাষাটি বলেছে "বিবৃতি শেষে অস্থায়ীদের মৃত্যু হয়, যদি না তারা রেফারেন্সের সীমাবদ্ধ থাকে, যদি তারা রেফারেন্সের সুযোগের বাইরে চলে যায় তবে তারা মারা যায়"। এই নিয়মটি প্রয়োগ করে, পরবর্তী বিবৃতিটির শুরুতে এটি x ইতিমধ্যে মারা গেছে বলে মনে হচ্ছে, কারণ এটি রেফারেন্সের জন্য আবদ্ধ নয় (সংকলকটি রেফ () কী দেয়) তা জানে না। এটি অবশ্য একটি অনুমান মাত্র।

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

3) ঠিক আছে, যদি আমি X& x = getx().ref();বিবৃতিটির শেষে মরে প্রায় এক্স সম্পর্কে ঠিক থাকি তবে সমস্যাগুলি সুস্পষ্ট।

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


2
@ এসবিকে: ১) আসলে, সঠিক বাক্যাংশটি হ'ল: "... সম্পূর্ণ প্রকাশের শেষে ..." ... আমি বিশ্বাস করি একটি "সম্পূর্ণ এক্সপ্রেশন" এমনটি হিসাবে সংজ্ঞায়িত করা হয় যা অন্য কোনও মত প্রকাশের উপ-প্রকাশ নয়। এটি সর্বদা "বিবৃতিটির সমাপ্তির" সমান কিনা, আমি নিশ্চিত নই।
এসবিআই

5
@sbk: 2) আসলে, আপনারা হয় rvalues (temporaries) সংশোধন করার অনুমতি দেওয়া। এটা তোলে প্রকার (বিল্ট-ইন-এর জন্য নিষিদ্ধ intইত্যাদি), কিন্তু এটা ব্যবহারকারী-সংজ্ঞায়িত ধরনের জন্য অনুমোদিত: (std::string("A")+"B").append("C")
এসবিআই

6
@ এসবিকে: ৩) স্ট্রস্ট্রপ অবিশ্বাস্য রেফারেন্সগুলিতে রুল্যুগুলি বাঁধাই না করার জন্য (ডি ও ই তে) যে কারণটি দিয়েছেন তা হ'ল, যদি আলেক্সি g()অবজেক্টটি সংশোধন করে (যা আপনি কোনও নন-কনস্ট্যান্ট রেফারেন্স গ্রহণের কোনও ফাংশন থেকে প্রত্যাশা করেছিলেন), এটি মরতে চলেছে এমন কোনও উপাদানকে পরিবর্তন করবে, সুতরাং যে কোনওভাবেই পরিবর্তিত মান পাওয়া যাবে না। তিনি বলেছেন যে এটি সম্ভবত একটি ত্রুটি।
এসবিআই

2
@ এসবিকে: আমি আপনাকে ক্ষুদ্ধ করলে আমি দুঃখিত, তবে আমি মনে করি না 2) নিটপিক করছে। আপনি এগুলি তৈরি না করে মানগুলি কেবল সীমাবদ্ধ নয় এবং আপনি সেগুলি বিল্ট-ইন না করাতে পরিবর্তন করতে পারবেন। উদাহরণস্বরূপ, স্ট্রিং উদাহরণ দিয়ে আমি কিছু ভুল করেছি (জেএফটিআর: আমি না), এটি বুঝতে আমার কিছুটা সময় লেগেছে, তাই আমি এই পার্থক্যটিকে গুরুত্ব সহকারে নেওয়ার ঝোঁক রাখছি।
sbi

5
আমি এসবিআই-র সাথে একমত - এই বিষয়টি মোটেই নিটপিক নয়। এটি মুভ সিমান্টিক্সের সমস্ত ভিত্তিতে যে শ্রেণির ধরণের মূল্যবোধগুলি নন-কনস্ট্যান্টকে সেরা রাখা হয়।
জোহানেস স্কাউব -

38

আপনার কোডে getx()একটি অস্থায়ী বস্তু, একটি তথাকথিত "মূল্য" প্রদান করে। আপনি বস্তুগুলিতে (যেমন। ভেরিয়েবল) অনুলিপিগুলি অনুলিপি করতে পারেন বা এগুলি রেফারেন্সগুলিতে আবদ্ধ করতে পারেন (যা তাদের জীবনকাল রেফারেন্সের জীবনের শেষ অবধি প্রসারিত করবে)। আপনি অ-নিরপেক্ষ রেফারেন্সগুলিতে মানগুলি আবদ্ধ করতে পারবেন না।

এক্সপ্রেশনটির শেষে মারা যেতে চলেছে এমন কোনও বিষয় দুর্ঘটনাক্রমে ব্যবহারকারীদের রোধ করার জন্য এটি একটি ইচ্ছাকৃত নকশার সিদ্ধান্ত ছিল:

g(getx()); // g() would modify an object without anyone being able to observe

আপনি যদি এটি করতে চান তবে আপনাকে প্রথমে একটি স্থানীয় অনুলিপি বা অবজেক্টের প্রথমে তৈরি করতে হবে বা একটি দৃ const় রেফারেন্সে আবদ্ধ করতে হবে:

X x1 = getx();
const X& x2 = getx(); // extend lifetime of temporary to lifetime of const reference

g(x1); // fine
g(x2); // can't bind a const reference to a non-const reference

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

void g(X&);   // #1, takes an ordinary (lvalue) reference
void g(X&&);  // #2, takes an rvalue reference

X x; 
g(x);      // calls #1
g(getx()); // calls #2
g(X());    // calls #2, too

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

class X {
  X(X&& rhs)
    : pimpl( rhs.pimpl ) // steal rhs' data...
  {
    rhs.pimpl = NULL; // ...and leave it empty, but deconstructible
  }

  data* pimpl; // you would use a smart ptr, of course
};


X x(getx()); // x will steal the rvalue's data, leaving the temporary object empty

2
হাই, এটি একটি দুর্দান্ত উত্তর। একটি জিনিস জানা দরকার, g(getx())কাজ করে না কারণ এটির স্বাক্ষর g(X& x)এবং get(x)একটি অস্থায়ী বস্তু ফেরত দেয়, তাই আমরা কোনও অস্থায়ী রেফারেন্সের সাথে একটি অস্থায়ী বস্তুর ( মূল্য ) আবদ্ধ করতে পারি না , সঠিক? এবং আপনার প্রথম কোড const X& x2 = getx();const X& x1 = getx();
পিসে

1
আমি এই লেখার 5 বছর পরে আমার উত্তরটিতে এই বাগটি নির্দেশ করার জন্য আপনাকে ধন্যবাদ! :-/হ্যাঁ, আপনার যুক্তিটি সঠিক, কিছুটা পিছন পিছনে হলেও: আমরা অস্থায়ীদেরকে অ- const(মূল্য) রেফারেন্সগুলিতে বেঁধে রাখতে পারি না এবং সুতরাং অস্থায়ীভাবে ফিরে আসা getx()(এবং না get(x)) লভ্য রেফারেন্সের সাথে আবদ্ধ হতে পারে না যেটির পক্ষে যুক্তি রয়েছে g()
এসবিআই

উম্ম, আপনি কী বোঝাতে চেয়েছিলেন getx()(এবং না get(x)) ?
সেক্সিবিস্ট

যখন আমি "... getx () (এবং (এক্স)) পাই না " , তখন আমি বোঝায় যে ফাংশনটির নাম getx(), এবং নয় get(x)(যেমন আপনি লিখেছেন)।
এসবিআই

এই উত্তর পরিভাষা মিশ্রিত। একটি মূল্যবোধ একটি অভিব্যক্তি বিভাগ। অস্থায়ী বস্তু হ'ল একটি বস্তু। একটি মূল্যায়ন একটি অস্থায়ী বস্তু বোঝাতে বা নাও পারে; এবং একটি অস্থায়ী বস্তু একটি মূল্য দ্বারা চিহ্নিত করা যেতে পারে বা নাও হতে পারে।
এমএম

16

আপনি যা দেখাচ্ছে তা অপারেটর চেইন অনুমোদিত।

 X& x = getx().ref(); // OK

এক্সপ্রেশনটি হ'ল 'গেটেক্স ()। রেফ ();' এবং এটি এক্স এর ক্ষেত্রে অ্যাসাইনমেন্টের পূর্বে সম্পূর্ণ হওয়ার জন্য কার্যকর করা হয়।

নোট করুন যে getx () কোনও রেফারেন্স দেয় না তবে স্থানীয় প্রেক্ষাপটে একটি সম্পূর্ণ গঠিত বস্তু formed অবজেক্টটি অস্থায়ী তবে এটি স্থির নয় , সুতরাং আপনাকে একটি মান গণনা করতে অন্যান্য পদ্ধতিতে কল করতে বা অন্যান্য পার্শ্ব প্রতিক্রিয়াগুলি ঘটতে দেয়।

// It would allow things like this.
getPipeline().procInstr(1).procInstr(2).procInstr(3);

// or more commonly
std::cout << getManiplator() << 5;

এর আরও ভাল উদাহরণের জন্য এই উত্তরটির শেষে দেখুন

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

রেফ () দ্বারা ফেরত মানটি একটি বৈধ রেফারেন্স তবে পদ্ধতিটি যে বস্তুর প্রত্যাবর্তন করছে তার জীবনকাল সম্পর্কে কোনও মনোযোগ দেয় না (কারণ এটি এর প্রসঙ্গে এই তথ্য থাকতে পারে না)। আপনি মূলত এর সমতুল্য কাজটি করেছেন:

x& = const_cast<x&>(getX());

কোনও অস্থায়ী অবজেক্টের দৃ const় রেফারেন্স সহ এটি করা ঠিক কারণ হ'ল মানটি অস্থায়ীর জীবনকাল রেফারেন্সের আয়ু পর্যন্ত প্রসারিত করে তাই অস্থায়ী বস্তুগুলির আয়ু বিবৃতিটির শেষের বাইরে প্রসারিত হয়।

সুতরাং কেবলমাত্র অবশিষ্ট প্রশ্নটি হল কেন স্ট্যান্ডার্ডগুলি বিবৃতিটির শেষের বাইরে বস্তুর আয়ু বাড়ানোর জন্য অস্থায়ীদের রেফারেন্সটিকে অনুমতি দিতে চায় না?

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

এই পরিস্থিতি সম্পর্কে চিন্তা করুন:

int getI() { return 5;}
int x& = getI();

x++; // Note x is an alias to a variable. What variable are you updating.

এই অস্থায়ী বস্তুর আজীবন প্রসারিত করা খুব বিভ্রান্তিকর হতে চলেছে।
নিম্নলিখিত যখন:

int const& y = getI();

আপনাকে এমন কোড দেবে যা এটি ব্যবহার এবং বোঝার জন্য স্বজ্ঞাত।

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


3
"সুতরাং কেবলমাত্র অবশিষ্ট প্রশ্নটি হল কেন স্ট্যান্ডার্ডগুলি বিবৃতিটির শেষের বাইরে বস্তুর আয়ু বাড়ানোর অনুমতি দেয় না?" হ্যাঁ, ওটাই! আপনি আমার প্রশ্ন বুঝতে । তবে আমি আপনার মতামতের সাথে একমত নই। আপনি "সংকলকটি খুব শক্ত করুন" বলেছিলেন তবে এটি কনস্ট্যান্ট রেফারেন্সের জন্য করা হয়েছিল। আপনি আপনার নমুনায় বলেছেন "নোট এক্স একটি ভেরিয়েবলের একটি উপনাম। আপনি কী পরিবর্তনশীল আপডেট করছেন।" সমস্যা নেই. এখানে অনন্য পরিবর্তনশীল (অস্থায়ী) রয়েছে। কিছু অস্থায়ী বস্তু (সমান 5 টি) পরিবর্তন করতে হবে।
আলেক্সি মালিস্তভ

@ মার্টিন: জটলা রেফারেন্সগুলি কেবল অবাস্তব নয়। পদ্ধতিতে পরে অ্যাক্সেস করা হলে এগুলি গুরুতর বাগগুলি নিয়ে যেতে পারে!
মিমি মিমি মিমি

1
@ অ্যালक्सी: নোট করুন যে এটিকে দৃ a় রেফারেন্সের সাথে আবদ্ধ করা একটি অস্থায়ী জীবনকালকে বাড়িয়ে তোলে এমন একটি ব্যতিক্রম যা ইচ্ছাকৃতভাবে যুক্ত করা হয়েছে (ম্যানুয়াল অপ্টিমাইজেশনের অনুমতি দেওয়ার জন্য টিটিবিওএমকে)। নন-কনস্ট্যান্ট রেফারেন্সগুলির জন্য এখানে কোনও ব্যতিক্রম যুক্ত হয়নি, কারণ একটি অ-সাময়িক রেফারেন্সের সাথে অস্থায়ী বাঁধাই সম্ভবত প্রোগ্রামার ত্রুটি হিসাবে দেখা গিয়েছিল।
এসবিআই

1
@ অ্যালেক্সি: একটি অদৃশ্য পরিবর্তনশীল একটি রেফারেন্স! অন্তর্নিহিত না।
মার্টিন ইয়র্ক

const_cast<x&>(getX());কোনও অর্থ নেই
কৌতূহলী

10

সি ++ এফএকিউ ( বোল্ডফ্যাসিং মাইন) এ কেন আলোচনা করা হয়:

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

void incr(int& a) { ++a; }
int i = 0;
incr(i);    // i becomes 1
incr(0);    // error: 0 is not an lvalue

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


সেই ফোর্তরান "শূন্য বাগ" দ্বারা কামড়ানো প্রোগ্রামারের মুখটি দেখে মজা হত! x * 0 দেয় x? কি? কি??
জন ডি

শেষ যুক্তিটি বিশেষত দুর্বল। উল্লেখ করার মতো কোনও সংকলক আসলে 0 থেকে 1 এর মান পরিবর্তন করতে পারে না, এমনকি incr(0);এমনভাবে ব্যাখ্যাও করতে পারে না। স্পষ্টতই, যদি এটি অনুমোদিত হয় তবে এটি একটি অস্থায়ী পূর্ণসংখ্যা তৈরি করা এবং এটিকে পাসিং হিসাবে ব্যাখ্যা করা হবেincr()
user3204459

6

মূল বিষয়টি হ'ল

g(getx()); //error

একটি যৌক্তিক ত্রুটি: gএর ফলাফলটি সংশোধন করছে getx()তবে পরিবর্তিত অবজেক্টটি পরীক্ষা করার কোনও সুযোগ আপনার নেই। যদি gএর প্যারামিটারটি সংশোধন করার প্রয়োজন না হয় তবে তার জন্য কোনও মূল্যমানের রেফারেন্সের দরকার পড়েনি, এটি মান বা কনস্টিটে রেফারেন্স দ্বারা প্যারামিটারটি নিতে পারে।

const X& x = getx(); // OK

বৈধ কারণ আপনার কখনও কখনও কোনও অভিব্যক্তির ফলাফল পুনরায় ব্যবহার করা প্রয়োজন এবং এটি একটি স্পষ্ট যে আপনি কোনও অস্থায়ী কোনও বিষয় নিয়ে কাজ করছেন।

তবে এটি তৈরি করা সম্ভব নয়

X& x = getx(); // error

বৈধ না করে g(getx())বৈধ, যা ভাষা ডিজাইনাররা প্রথমে এড়াতে চাইছিলেন।

g(getx().ref()); //OK

বৈধ কারণ thisকারণগুলি পদ্ধতিগুলি কেবলমাত্র কনস্ট্যান্ট নেস সম্পর্কে জানে , তারা জানে না যে সেগুলি কোনও মূল্যবান বা কোনও মূল্যমানের উপর ডাকা হয়েছিল কিনা।

সি ++ এর মতো সর্বদা আপনার এই নিয়মটির পক্ষে একটি কার্যনির্বাহী কাজ রয়েছে তবে আপনাকে সংকলকটি সিগন্যাল করতে হবে যা আপনি জানেন যে আপনি সুস্পষ্ট হয়ে কী করছেন:

g(const_cast<x&>(getX()));

5

এটি কেন অনুমোদিত নয় তা মূল প্রশ্নের মতোই পরিষ্কার উত্তর দেওয়া হয়েছে: "কারণ এটি সম্ভবত একটি ত্রুটি"।

এফডাব্লুআইডাব্লু, আমি ভেবেছিলাম যে এটি কীভাবে করা যায় তা আমি প্রদর্শন করব, যদিও আমি এটি একটি ভাল কৌশল বলে মনে করি না।

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

// Assuming: void Person::GetNameAndAddr(std::string &name, std::string &addr);
string name;
person.GetNameAndAddr(name, string()); // don't care about addr

পূর্ববর্তী উত্তরে যেমন বর্ণনা করা হয়েছে, এটি সংকলন করে না। তবে এটি সংকলন করে এবং সঠিকভাবে কাজ করে (আমার সংকলক সহ):

person.GetNameAndAddr(name,
    const_cast<string &>(static_cast<const string &>(string())));

এটি কেবল দেখায় যে আপনি সংকলককে মিথ্যা বলতে ingালাই ব্যবহার করতে পারেন। স্পষ্টতই, অব্যর্থযুক্ত স্বয়ংক্রিয় ভেরিয়েবলটি ঘোষণা করা এবং পাস করা আরও পরিষ্কার হবে:

string name;
string unused;
person.GetNameAndAddr(name, unused); // don't care about addr

এই কৌশলটি পদ্ধতির সুযোগে একটি অপ্রয়োজনীয় স্থানীয় পরিবর্তনশীল প্রবর্তন করে। যদি কোনও কারণে আপনি এটিকে পরে পদ্ধতিতে ব্যবহার করা থেকে বিরত রাখতে চান, উদাহরণস্বরূপ, বিভ্রান্তি বা ত্রুটি এড়াতে, আপনি এটি স্থানীয় ব্লকে লুকিয়ে রাখতে পারেন:

string name;
{
    string unused;
    person.GetNameAndAddr(name, unused); // don't care about addr
}

- ক্রিস


4

কেন আপনি কখনও চান X& x = getx();? X x = getx();আরভিওতে কেবল ব্যবহার এবং নির্ভর করুন।


3
Becouse আমি কল করতে চান g(getx())বদলেg(getx().ref())
আলেক্সি Malistov

4
@ আলেক্সি, এটি আসল কারণ নয়। যদি আপনি এটি করেন তবে আপনার যেকোন জায়গায় লজিকাল ত্রুটি রয়েছে, কারণ gএমন কোনও কিছু পরিবর্তন করতে চলেছে যা আপনি আর হাত পেতে পারেন না।
জোহানেস স্কাউব - 21

3
@ জোহানেস শ্যাব-লিটব হয়ত তার পাত্তা দিচ্ছেন না।
কৌতূহলী

" আরভিও'র উপর নির্ভর করুন " বাদে একে "আরভিও" বলা হয় না।
কৌতূহলী

2
@ কুরিয়াসগুয়ে: এটি এটির জন্য একটি অত্যন্ত স্বীকৃত শব্দ। এটিকে "আরভিও" হিসাবে উল্লেখ করার সাথে একেবারেই কোনও ভুল নেই।
কুকুরছানা

4

অশুভ কাজটির সাথে 'পরিবর্তনযোগ্য' কীওয়ার্ড জড়িত। আসলে মন্দ হওয়া পাঠকের অনুশীলন হিসাবে ছেড়ে যায়। বা এখানে দেখুন: http://www.ddj.com/cpp/184403758


3

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

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

তবে এই পুরো ধারণাটি অত্যন্ত বিভ্রান্তিকর। উদাহরণ const X &x = X();হিসাবে xরেফারেন্স হিসাবে অস্থায়ী শেষ করতে হবে , কিন্তু const X &x = X().ref();না (কে ref()আসলে জানেন কি )। পরবর্তী ক্ষেত্রে, ডিস্ট্রাক্টর Xএই লাইনের শেষে ডাকা হয়। (এটি একটি তুচ্ছ ত্রুটিযুক্ত ডেস্ট্রাক্টরের সাথে পর্যবেক্ষণযোগ্য))

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

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

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

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


2

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

আপনার উদাহরণে getX () একটি কনস্টেট এক্স ফিরিয়ে দেয় না যাতে আপনি রেফ () কে ঠিক একইভাবে কল করতে পারবেন যেভাবে আপনি এক্স ()। রেফ () কল করতে পারেন। আপনি একটি নন কনস্ট রেফার ফিরিয়ে দিচ্ছেন এবং তাই নন কনস্ট পদ্ধতিতে কল করতে পারেন, আপনি যা করতে পারবেন না তা হ'ল রেফটিকে নন কনস্ট রেফারেন্সকে বরাদ্দ করুন।

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


1

আমার এমন একটি পরিস্থিতি আছে যেখানে আমি ভাগ করে নিতে চাই যেখানে আলেক্সি যা চাইছে তা করতে পারতাম। একটি মায়া সি ++ প্লাগইনে নোডের বৈশিষ্ট্যে একটি মান পেতে আমাকে নীচের শেনানিগান করতে হবে:

MFnDoubleArrayData myArrayData;
MObject myArrayObj = myArrayData.create(myArray);   
MPlug myPlug = myNode.findPlug(attributeName);
myPlug.setValue(myArrayObj);

এটি লেখার জন্য ক্লান্তিকর, তাই আমি নিম্নলিখিত সহায়িকার ফাংশনগুলি লিখেছিলাম:

MPlug operator | (MFnDependencyNode& node, MObject& attribute){
    MStatus status;
    MPlug returnValue = node.findPlug(attribute, &status);
    return returnValue;
}

void operator << (MPlug& plug, MDoubleArray& doubleArray){
    MStatus status;
    MFnDoubleArrayData doubleArrayData;
    MObject doubleArrayObject = doubleArrayData.create(doubleArray, &status);
    status = plug.setValue(doubleArrayObject);
}

এবং এখন আমি পোস্টটির শুরু থেকেই কোডটি লিখতে পারি:

(myNode | attributeName) << myArray;

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

ঠিক আছে, এটা আমার দৃশ্যপট। কেবল ভেবেছি আমি একটি উদাহরণ দেখাব যেখানে একজন আলেক্সি বর্ণনা করে যা করতে চায় আমি সমস্ত সমালোচনা এবং পরামর্শ স্বাগত জানাই!

ধন্যবাদ।

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