Professional Documents
Culture Documents
მარცხენა და მარჯვენა სიდიდეები (lvalue, rvalue) lvalue -ზე რეფერენსი rvalue-ზე რეფერენსი რეფერენსების ჩამოყრა უნივერსალური რეფერენსი (გადამწოდებელი რეფერენსი) წყაროები
მარცხენა და მარჯვენა სიდიდეები (lvalue, rvalue) lvalue -ზე რეფერენსი rvalue-ზე რეფერენსი რეფერენსების ჩამოყრა უნივერსალური რეფერენსი (გადამწოდებელი რეფერენსი) წყაროები
რეფერენსები
განხილული საკითხები:
მარცხენა და მარჯვენა სიდიდეები (lvalue, rvalue)
lvalue -ზე რეფერენსი >>>
rvalue-ზე რეფერენსი >>>
რეფერენსების ჩამოყრა >>>
უნივერსალური რეფერენსი (გადამწოდებელი რეფერენსი) >>>
წყაროები >>>
Page 1 of 8
უფრო საინტერესო მაგალითები უკავშირდება ფუნქციებს. ფუნქციის გამოძახება წარმოადგენს
rvalue-ს, თუ ფუნქცია აბრუნებს მნიშვნელობას. თუ რეფერენსით აბრუნებს- მაშინ lvalue-საც.
მაგალითად, back() მეთოდი ვექტორში.
თავიდან C ენაში განსაზღვრეს lvalue, როგორც „სიდიდე რომელიც შესაფერისია მინიჭების
მარცხენა მხარისთვის“. მოგვიანებით ISO C-ში დაამატეს const სიტყვა. თუ ობიექტის
განაცხადში მონაწილეობს const, ეს ობიექტი არ არის განახლებადი (modifiable).
შესაძლებელია lvalue-ების გარდაქმნა rvalue-ებად, რასაც ხშირად შევხვდებით შემდეგში.
პირიქით შეუძლებელია გარდაქმნა.
ნიშნავს, რომ x ცვლადს დაერქვა მეორე სახელი y, და ეს ობიექტები მეხსიერების ერთი და იმავე
ნაკვეთს აღნიშნავენ. შესაძლებელია რომ უკვე არსებულ lvalue ობიექტს დავარქვათ მეორე
სახელი, რომელსაც შეზღუდული ექნება ობიექტის განახლების შესაძლებლობა:
const T& y = x; // (1)
Page 3 of 8
2 A T& A&1
3 A T&& A&&1
4 A& T A&1
5 A& T& A&
6 A& T&& A&
7 A&& T A&&1
8 A&& T& A&
9 A&& T&& A&&
შენიშვნა
1
. რეფერენსების ჩამოყრის წესი არ მუშაობს როდესაც T და TR, არცერთი არაა რეფერენსის ტიპი
p=004FF9F0
&y=004FF9F0
Press any key to continue . . .
გვიჩვენებს რომ y არის რეფერენსი მეხსიერების იმ მონაკვეთზე, რომელიც შეიქმნა ფუნქციაში
და რომელიც დაბრუნდა რეფერენსით. ფუნქცია ძალიან ხელოვნურია, თუმცა
თვალსაჩინოებისთვის გამოსადეგი.
Page 4 of 8
შემთხვევა 8. როდესაც T არის A&&, ხოლო RT არის T&. განვიხილოთ მარტივი შემთხვევა,
როდესაც A არის მთელი რიცხვების ტიპი. მარჯვენა მნიშვნელობა გავამზადოთ შემდეგი
ფუნქციის გამოძახებით:
int foo()
{
return 5;
}
განვიხილოთ:
int main()
{
using T = add_rvalue_reference_t<int>;
T x{ foo() }; // (4)
cout << "&x=" << &x << endl;
T& y{ x };
cout << "&y=" << &y << endl;
}
(4) განაცხადის შემდეგ, x არის კონვერტირებადი ჩვეუელებრივ მთელზე, ხოლო შედეგი
&x=00B6F808
&y=00B6F808
Press any key to continue . . .
გვიჩვენებს, რომ y ებმება მთელი ტიპის ცვლადის მისამართს. შინაარსისგან განყენებულად,
საკმარისია კურსორი გადავატაროთ y ცვლადს, რომ გამოჩნდება კარნახი:
T TR var-ის ტიპი
1 A const T const A1
2 const A volatile T& const volatile A&1
3 A const T&& const A&&1
4 A& const T A&1
5 const A& volatile T& const A&
6 const A& T&& const A&
7 A&& const T A&&1
8 const A&& volatile T& const A&
9 const A&& T&& const A&&
შენიშვნა
1
. რეფერენსების ჩამოყრის წესი არ მუშაობს როდესაც T და TR არცერთი არაა რეფერენსის ტიპი
Page 5 of 8
<<< უნივერსალური რეფერენსი (გადამწოდებელი რეფერენსი)
იმისათვის რომ გავაკეთოთ განაცხადი რაიმე T ტიპის rvalue-ზე რეფერენსი, ვწერთ T&& -ს.
მაგრამ ზოგიერთ შემთხვევში შექმნილი ობიექტი აღმოჩნდება სხვა ტიპის. მაგალითად:
void f(Widget&& param); // rvalue-ზე რეფერენსი
Widget&& var1 = Widget(); // rvalue-ზე რეფერენსი
auto&& var2 = var1; // ეს არაა rvalue-ზე რეფერენსი
template<typename T>
void f(std::vector<T>&& param); // rvalue-ზე რეფერენსი
template<typename T>
void f(T&& param); // არაა rvalue-ზე რეფერენსი
„T&&“-ს აქვს ორი განსხვავებული მნიშვნელობა. ერთი არის rvalue-ზე რეფერენსი. ასეთი
რეფერენსები იქცევიან ზუსტად ისე, რასაც მისგან ელიან: ისინი ებმებიან მხოლოდ rvalue-ებს
და მათი პირველადი „არსებობის აზრი“ არის ისეთი ობიექტების ამოცნობა, რომლებიდანაც
შესაძლებელია გადაადგილება.
„T&&“-ს სხვა მნიშვნელობა არის რეფერენსი ან rvalue-ზე ან lvalue-ზე. ასეთი რეფერენსი საწყის
კოდში გამოიყურება rvalue-ზე რეფერენსივით (ე.ი.„T&&“), მაგრამ შესაძლოა მოქმედებდეს
lvalue-ზე რეფერენსის მსგავსად (ე.ი.„T&“). მათი ორმაგი ბუნება საშუალებას აძლევთ რომ მიებან
როგორც rvalue-ებს (rvalue-ზე რეფერენსების მსგავსად), ასევე lvalue-ებს (lvalue-ზე
რეფერენსების მსგავსად). შემდეგ, მათ შეუძლიათ მიებან const ან არა-const ობიექტებს, volatile ან
არა- volatile ობიექტებს, ისეთებსაც კი რომლებიც ერთდროულად ორივეა, const-იც და volatile-
იც. ასეთი უპრეცენდენტოდ მოქნილი რეფერენსები იმსახურებენ საკუთარ სახელს. სკოტ
მაიერსი მათ უწოდებს უნივერსალურ რეფერენსებს (universal references). C++ community-ის
რამდენიმე წევრი მათ მოიხსენებს სახელით: გადამწოდებელი რეფერენსი (forwarding references).
როგორც მარტივი მაგალითი, Visual Studio-ში თუ ავკრეფთ სტრიქონებს:
int&& m{ 99 };
auto&& n = m;
და კურსორს გადავატარებთ თავზე n ცვლადს, გამოჩნდება int &n გზავნილი. m ცვლადის თავზე
გადატარებისას ჩანს მის განაცხადში მითითებული ტიპი.
უნივერსალური რეფერენსი ორ ვითარებაში ჩნდება. უფრო გავრცელებული არის თარგის
პარამეტრები, როგორც ზემოთ მოყვანილ ნიმუშში იყო:
template<typename T>
void f(T&& param); // param არის უნივერსალური რეფერენსი
მეორე ვითარება არის auto განაცხადი, როგორც ზემოთ მოყვანილ მაგალითში იყო:
auto&& var2 = var1; // var2 არის უნივერსალური რეფერენსი
Page 6 of 8
უნივერსალური რეფერენსი - რეფერენსია, ამიტომ ინიციალება აუცილებელია. (უნივერსალური
რეფერენსის) მაინიციალებელი განსაზღვრავს თუ ზუსტად რას წარმოადგენს უნივერსალური
რეფერენსი - rvalue-ზე რეფერენსს თუ lvalue-ზე რეფერენსს. თუ მაინიციალებელი rvalue არის,
მაშინ უნივერსალური რეფერენსი შეესაბამება rvalue-ზე რეფერენსს. თუ მაინიციალებელი lvalue
არის, მაშინ უნივერსალური რეფერენსი შეესაბამება lvalue-ზე რეფერენსს. იმ უნივერსალური
რეფერენსებისთვის, რომლებიც ფუნქციის პარამეტრებია, მაინიციალებელი მიეწოდება
გამოძახების ადგილიდან:
template<typename T>
void f(T&& param); // param არის უნივერსალური რეფერენსი
Widget w;
f(w); // lvalue მიეწოდება f-ს; param-ის ტიპი არის
// Widget& (ე.ი, lvalue რეფერენსი)
ადრე აღნიშნული იყო, რომ auto ცვლადები შესაძლოა აგრეთვე იყვნენ უნივერსალური
რეფერენსები. უფრო ზუსტები რომ ვიყოთ, auto&& ტიპით გამოცხადებული ცვლადები არიან
უნივერსალური რეფერენსები, რადგან ტიპის გამოცნობა ხდება როდესაც მათ აქვთ სწორი
ფორმა („T&&“). auto უნივერსალური რეფერენსები არაა ისეთი გავრცელებული როგორც
ფუნქციის თარგის პარამტრებისთვის გამოყენებულები, მაგრამ ისინი შიგადაშიგ
ამოტივტივდებიან ხოლმე C++11-ში. C++14-ში ისინი ბევრად ხშირად გამოდიან ზედაპირზე,
რადგან C++14-ის ლამბდა გამოსახულებებს შეუძლიათ auto&& პარამეტრების გამოცხადება.
<<< წყაროები:
1. Scott Meyers. Effective Modern C++. O’Reilly, 2014.
2. https://msdn.microsoft.com/en-us/library/f90831hc.aspx
3. http://eli.thegreenplace.net/2011/12/15/understanding-lvalues-and-rvalues-in-c-and-c
4. https://www.ibm.com/support/knowledgecenter/en/SSGH3R_12.1.0/com.ibm.xlcpp121.aix.
doc/language_ref/reference_collapsing.html
Page 8 of 8