"এটির জন্য মূল রেফারেন্স" কী?


238

ঝাঁকুনির সি ++ 11 স্থিতি পৃষ্ঠায় "এটির জন্য মূল্যের রেফারেন্স" নামে একটি প্রস্তাব এসেছে ।

আমি মূল্যের রেফারেন্সগুলি সম্পর্কে বেশ কিছুটা পড়েছি এবং সেগুলি বুঝতে পেরেছি, তবে আমি মনে করি না যে আমি এই সম্পর্কে জানি। পদগুলি ব্যবহার করে আমি ওয়েবে প্রচুর সংস্থানও খুঁজে পাইনি।

পৃষ্ঠায় প্রস্তাবের কাগজের একটি লিঙ্ক রয়েছে: এন 2439 ( এটির জন্য সরু শব্দার্থিক শব্দগুলি * প্রসারিত করা), তবে আমি সেখান থেকে খুব বেশি উদাহরণ পাচ্ছি না।

এই বৈশিষ্ট্যটি কী সম্পর্কে?

উত্তর:


293

প্রথমত, "এটির জন্য রেফ-কোয়ালিফায়ার" এটি একটি "বিপণন বিবৃতি"। *thisকখনই পরিবর্তন হয় না, এই পোস্টের নীচে দেখুন। যদিও এই শব্দটির সাহায্যে এটি বোঝার সহজ উপায়।

এর পরে, নিম্নলিখিত কোড বেছে ফাংশন উপর ভিত্তি করে বলা হবে ; ref-কোয়ালিফায়ার ফাংশনের "অন্তর্নিহিত বস্তুর পরামিতি" এর :

// t.cpp
#include <iostream>

struct test{
  void f() &{ std::cout << "lvalue object\n"; }
  void f() &&{ std::cout << "rvalue object\n"; }
};

int main(){
  test t;
  t.f(); // lvalue
  test().f(); // rvalue
}

আউটপুট:

$ clang++ -std=c++0x -stdlib=libc++ -Wall -pedantic t.cpp
$ ./a.out
lvalue object
rvalue object

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

struct test2{
  std::unique_ptr<int[]> heavy_resource;

  test2()
    : heavy_resource(new int[500]) {}

  operator std::unique_ptr<int[]>() const&{
    // lvalue object, deep copy
    std::unique_ptr<int[]> p(new int[500]);
    for(int i=0; i < 500; ++i)
      p[i] = heavy_resource[i];

    return p;
  }

  operator std::unique_ptr<int[]>() &&{
    // rvalue object
    // we are garbage anyways, just move resource
    return std::move(heavy_resource);
  }
};

এটি কিছুটা স্বীকৃত হতে পারে তবে আপনার ধারণাটি নেওয়া উচিত।

মনে রাখবেন আপনি সিভি-বাছাইকারী ( constএবং volatile) এবং রেফ-কোয়ালিফায়ার ( &এবং &&) একত্রিত করতে পারেন ।


দ্রষ্টব্য: এখানে অনেক স্ট্যান্ডার্ড কোট এবং ওভারলোড রেজোলিউশন ব্যাখ্যা!

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

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

প্রথমত, সদস্য ফাংশনগুলির জন্য ওভারলোড রেজোলিউশন কীভাবে কাজ করে তা দেখতে গুরুত্বপূর্ণ:

§13.3.1 [over.match.funcs]

p2 প্রার্থী ফাংশনগুলির সেটটিতে একই আর্গুমেন্ট তালিকার বিপরীতে সমাধান করতে সদস্য এবং অ-সদস্য উভয় ফাংশন থাকতে পারে। সুতরাং যে যুক্তি এবং পরামিতি তালিকাগুলি এই ভিন্ন ভিন্ন সেট মধ্যে তুলনাযোগ্য, একটি সদস্য ফাংশন একটি অতিরিক্ত পরামিতি বলে মনে করা হয়, যা অন্তর্ভুক্ত অবজেক্ট প্যারামিটার বলা হয়, যা বস্তুর প্রতিনিধিত্ব করে যার জন্য সদস্য ফাংশন বলা হয়েছে । [...]

p3 একইভাবে, যখন উপযুক্ত হয়, প্রসঙ্গটি আর্গুমেন্টের তালিকাটি তৈরি করতে পারে যাতে অবজেক্টটি চালিত হতে বোঝাতে কোনও অন্তর্নিহিত অবজেক্ট আর্গুমেন্ট থাকে।

আমাদের এমনকি সদস্য ও অ-সদস্যের কার্যকারিতা তুলনা করা কেন প্রয়োজন? অপারেটর ওভারলোডিং, এজন্যই। এই বিবেচনা:

struct foo{
  foo& operator<<(void*); // implementation unimportant
};

foo& operator<<(foo&, char const*); // implementation unimportant

আপনি নীচেরগুলি অবশ্যই ফ্রি ফাংশনটি কল করতে চান, তাই না?

char const* s = "free foo!\n";
foo f;
f << s;

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

পি 4 অ স্থিতিশীল সদস্য ফাংশনের জন্য, অন্তর্নিহিত বস্তুর প্যারামিটারের ধরণ

  • "এ lvalue রেফারেন্স সিভি X কাজকর্মের জন্য" একটি ছাড়া ঘোষিত সুত্র-কোয়ালিফায়ার বা & সুত্র-কোয়ালিফায়ার

  • রেফ-কোয়ালিফায়ারের সাথে ঘোষিত ফাংশনগুলির জন্য " সিভি সম্পর্কিত মূল্যের রেফারেন্স X"&&

Xফাংশনটি কোন শ্রেণীর সদস্য এবং সিভি হল সদস্য ফাংশন ঘোষণায় সিভি-যোগ্যতা where [...]

p5 ওভারলোড রেজোলিউশন চলাকালীন [...] [টি] তিনি আপত্তিজনক পরামিতি [...] সম্পর্কিত পরিচয়টি ধরে রাখছেন কারণ সম্পর্কিত যুক্তিতে রূপান্তরগুলি এই অতিরিক্ত নিয়ম মানবে:

  • অন্তর্নিহিত অবজেক্ট প্যারামিটারের জন্য আর্গুমেন্ট ধরে রাখতে কোনও অস্থায়ী বস্তু চালু করা যায় না; এবং

  • কোনও ব্যবহারকারীর দ্বারা সংজ্ঞায়িত রূপান্তরগুলি এর সাথে কোনও প্রকারের মিলটি অর্জন করতে প্রয়োগ করা যাবে না

[...]

(শেষ বিটের ঠিক অর্থ হ'ল আপনি সদস্য ফাংশন (বা অপারেটর) নামক বস্তুর অন্তর্নিহিত রূপান্তরগুলির ভিত্তিতে ওভারলোড রেজোলিউশনকে প্রতারণা করতে পারবেন না))

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

void f1(test&); // will only match lvalues, linked to 'void test::f() &'
void f2(test&&); // will only match rvalues, linked to 'void test::f() &&'

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

// first call to 'f' in 'main'
test t;
f1(t); // 't' (lvalue) can match 'test&' (lvalue reference)
       // kept in overload-set
f2(t); // 't' not an rvalue, can't match 'test&&' (rvalue reference)
       // taken out of overload-set

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

// second call to 'f' in 'main'
f1(test()); // 'test()' not an lvalue, can't match 'test&' (lvalue reference)
            // taken out of overload-set
f2(test()); // 'test()' (rvalue) can match 'test&&' (rvalue reference)
            // kept in overload-set

তবে খেয়াল করুন যে, আমরা যদি কোনও রেফ-কোয়ালিফায়ার (এবং যেমন ফাংশনটি ওভারলোড না করে) সরবরাহ না করতাম, তবে এটি কোনও ফলাফলের f1 সাথে মেলে (এখনও §13.3.1):

পি 5 [...] রেফ-কোয়ালিফায়ার ছাড়াই ঘোষিত অ স্থিতিশীল সদস্য ফাংশনের জন্য একটি অতিরিক্ত নিয়ম প্রযোজ্য:

  • এমনকি যদি অন্তর্নিহিত অবজেক্ট প্যারামিটারকে constযোগ্যতা নাও দেওয়া হয়, তবুও একটি মূল্যায়ন প্যারামিটারের সাথে আবদ্ধ হতে পারে যতক্ষণ না অন্য সমস্ত ক্ষেত্রে যুক্তিটি অন্তর্নিহিত অবজেক্ট প্যারামিটারের ধরণে রূপান্তর করা যায়।
struct test{
  void f() { std::cout << "lvalue or rvalue object\n"; }
};

int main(){
  test t;
  t.f(); // OK
  test().f(); // OK too
}

এখন, কেন নিকোলের উত্তর অন্ততপক্ষে ভুল। তিনি বলেন:

দ্রষ্টব্য যে এই ঘোষণাটি এর ধরণের পরিবর্তন করে *this

যে ভুল, *thisহয় সবসময় একটি lvalue:

§5.3.1 [expr.unary.op] p1

ইউনারী *অপারেটর সঞ্চালিত অপ্রত্যক্ষ্যতার : অভিব্যক্তি যা তা প্রয়োগ করা একটি বস্তু টাইপ একটি পয়েন্টার, অথবা একটি ফাংশন টাইপ একটি পয়েন্টার হইবে এবং ফলাফল একটি lvalue হয় বস্তু বা ফাংশন যা অভিব্যক্তি পয়েন্ট উল্লেখ।

§9.3.2 [class.this] p1

অ-স্থিতিশীল (9.3) সদস্য ফাংশনের thisমূল শব্দের মধ্যে কীওয়ার্ডটি একটি মূল্যবান প্রকাশ হয় যার মূল্যটি সেই বস্তুর ঠিকানা যেখানে ফাংশন বলা হয়। ধরণ thisএকটি বর্গ সদস্য ফাংশনে Xহয় X*। [...]


আমি বিশ্বাস করি "পরিবর্তনের পরে" বিভাগের ঠিক পরে প্যারান্টারগুলি 'পরীক্ষার' পরিবর্তে 'ফু' হওয়া উচিত।
রায়ানার

@ আরায়নার: ভাল সন্ধান, ধন্যবাদ প্যারামিটার না হলেও ফাংশনগুলির শ্রেণি শনাক্তকারী ভুল। :)
Xeo

ওফস দুঃখিত, আমি খেলনা ক্লাস নামক পরীক্ষার কথা ভুলে গিয়েছিলাম যখন আমি সেই অংশটি পড়েছি এবং ভেবেছিলাম
ফু এর

এই কন্সট্রাকটর সঙ্গে সম্পন্ন করা যেতে পারে: MyType(int a, double b) &&?
জার্মান ডায়াগো

2
"এর ধরণের * এর কখনই পরিবর্তন হয় না" আপনার সম্ভবত কিছুটা স্পষ্ট হওয়া উচিত যে এটি আর / এল-মান যোগ্যতার ভিত্তিতে পরিবর্তিত হয় না। তবে এটি কনস্ট / নন-কনস্টের মধ্যে পরিবর্তন করতে পারে।
xaxxon

78

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

struct S {
  S& operator ++(); 
  S* operator &(); 
};
S() = S();      // rvalue as a left-hand-side of assignment!
S& foo = ++S(); // oops, dangling reference
&S();           // taking address of rvalue...

ল্যাভেলু রেফ-কোয়ালিফায়াররা এই সমস্যাগুলি সমাধান করে:

struct S {
  S& operator ++() &;
  S* operator &() &;
  const S& operator =(const S&) &;
};

এখন অপারেটরগুলি বিল্টিন ধরণের মতো কাজ করে, কেবলমাত্র লভ্য গ্রহণ করে।


28

ধরা যাক আপনার ক্লাসে দুটি ফাংশন রয়েছে, একই নাম এবং স্বাক্ষর উভয়ই। তবে তাদের মধ্যে একটি ঘোষণা করা হয়েছে const:

void SomeFunc() const;
void SomeFunc();

যদি কোনও শ্রেণীর উদাহরণ না হয় const, ওভারলোড রেজোলিউশনটি অগ্রাধিকার হিসাবে অ-কনস্ট্যান্ট সংস্করণ নির্বাচন করবে। উদাহরণটি যদি হয় constতবে ব্যবহারকারী কেবল constসংস্করণটি কল করতে পারে । এবং thisপয়েন্টারটি constপয়েন্টার, সুতরাং উদাহরণটি পরিবর্তন করা যায় না।

"এর জন্য আর-মান রেফারেন্স" আপনাকে অন্য একটি বিকল্প যুক্ত করার অনুমতি দেয়:

void RValueFunc() &&;

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

Object foo;
foo.RValueFunc(); //error: no `RValueFunc` version exists that takes `this` as l-value.
Object().RValueFunc(); //calls the non-const, && version.

এইভাবে, আপনি কোনও আর-মান দিয়ে অ্যাক্সেস করা হচ্ছে কিনা তার ভিত্তিতে আপনি আচরণকে বিশেষজ্ঞ করতে পারেন।

মনে রাখবেন যে আপনাকে আর-মান রেফারেন্স সংস্করণ এবং অ-রেফারেন্স সংস্করণগুলির মধ্যে ওভারলোড করার অনুমতি দেওয়া হচ্ছে না। এটি হ'ল, যদি আপনার একটি সদস্য ফাংশন নাম থাকে তবে এর সমস্ত সংস্করণ হয় l / r- মান কোয়ালিফায়ার ব্যবহার করে this, বা সেগুলির কোনওটিই করে না। আপনি এটি করতে পারবেন না:

void SomeFunc();
void SomeFunc() &&;

আপনার অবশ্যই এটি করা উচিত:

void SomeFunc() &;
void SomeFunc() &&;

দ্রষ্টব্য যে এই ঘোষণাটি এর ধরণের পরিবর্তন করে *this। এর অর্থ হ'ল &&সংস্করণগুলি সমস্ত সদস্যকে আর-মান উল্লেখ হিসাবে অ্যাক্সেস করে। সুতরাং সহজেই অবজেক্টের মধ্যে থেকে সরানো সম্ভব হয়। প্রস্তাবনার প্রথম সংস্করণে দেওয়া উদাহরণটি হ'ল (দ্রষ্টব্য: সি ++ 11 এর চূড়ান্ত সংস্করণ দিয়ে নিম্নলিখিতটি সঠিক নাও হতে পারে; এটি সরাসরি এই "প্রস্তাবের" আর-মান থেকে সরাসরি):

class X {
   std::vector<char> data_;
public:
   // ...
   std::vector<char> const & data() const & { return data_; }
   std::vector<char> && data() && { return data_; }
};

X f();

// ...
X x;
std::vector<char> a = x.data(); // copy
std::vector<char> b = f().data(); // move

2
আমার মনে হয় std::moveআপনার দ্বিতীয় সংস্করণটি দরকার, না? এছাড়াও, কেন মূল মূল্য রেফারেন্স?
Xeo

1
@ শিও: কারণ প্রস্তাবটিতে উদাহরণটি এটাই ছিল; এটি এখনও বর্তমান সংস্করণে কাজ করে কিনা আমার কোনও ধারণা নেই। আর-মান রেফারেন্স রিটার্নের কারণ হ'ল আন্দোলনটি ক্যাপচারকারী ব্যক্তির উপর হওয়া উচিত। এটি এখনও হওয়া উচিত নয়, কেবলমাত্র যদি সে এটির পরিবর্তে একটি মানের পরিবর্তে &&& এ সংরক্ষণ করতে চায়।
নিকল বোলাস

3
ঠিক আছে, আমি আমার দ্বিতীয় প্রশ্নটির কারণটি ভেবেছিলাম। আমি ভাবছি যদিও, কোনও অস্থায়ী সদস্যের কোনও অলৌকিক রেফারেন্স কি সেই অস্থায়ী বা তার সদস্যের আজীবন দীর্ঘায়িত করে? আমি শপথ করতে পারলাম কিছুক্ষণ আগে এই সম্পর্কে একটি প্রশ্ন দেখেছি ...
Xeo

1
@ শিও: এটি সম্পূর্ণ সত্য নয়। ওভারলোড রেজোলিউশনটি সর্বদা নন-কনস্ট্যান্ট সংস্করণটি উপস্থিত থাকলে তা চয়ন করবে। কনস্টের সংস্করণটি পেতে আপনার একটি কাস্ট করতে হবে। আমি স্পষ্ট করে পোস্টটি আপডেট করেছি।
নিকল বোলাস

15
আমি ভেবেছিলাম যে আমি ব্যাখ্যা করতে পারি, সর্বোপরি আমি সি ++ 11 এর জন্য এই বৈশিষ্ট্যটি তৈরি করেছি)) Xeo জোর দিয়েই ঠিক বলেছে যে এটির ধরণটি পরিবর্তন হয় না *this, তবে আমি বুঝতে পারি যে বিভ্রান্তিটি কোথা থেকে এসেছে। এটি কারণ কারণ রেফ-কোয়ালিফায়ার ওভারলোড রেজোলিউশন এবং ফাংশন কল চলাকালীন "এই" (এখানে উদ্দেশ্যগুলি রেখে দেওয়া কোটস!) অবজেক্টে আবদ্ধ (বা "লুকানো") ফাংশন প্যারামিটারের ধরন পরিবর্তন করে। সুতরাং, *thisজিয়ো ব্যাখ্যা অনুসারে এর কোনও পরিবর্তন স্থির হয়নি। পরিবর্তে, এটা lvalue- বা rvalue-রেফারেন্স করতে "hiddden" প্যারামিটারের পরিবর্তন ঠিক constফাংশন কোয়ালিফায়ার এটা তোলে constইত্যাদি ..
bronekk
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.