স্টাড :: :: সরানো () কীভাবে আরভ্যালুতে মান স্থানান্তর করে?


103

আমি নিজেকে খুঁজে পেয়েছি সম্পূর্ণরূপে এর যুক্তি বুঝতে পারছি না std::move()

প্রথমদিকে, আমি এটি গুগল করেছিলাম তবে মনে হয় কেবল কীভাবে ব্যবহার করতে হবে std::move()তার নথিতে রয়েছে , এর কাঠামোটি কীভাবে কাজ করে তা নয়।

আমি বলতে চাইছি, টেমপ্লেট সদস্যের ফাংশনটি কী তা আমি জানি তবে যখন আমি std::move()ভিএস 2010-এ সংজ্ঞাটি দেখি তখনও এটি বিভ্রান্তিকর।

std :: اقدام () এর সংজ্ঞাটি নীচে যায়।

template<class _Ty> inline
typename tr1::_Remove_reference<_Ty>::_Type&&
    move(_Ty&& _Arg)
    {   // forward _Arg as movable
        return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg);
    }

আমার কাছে প্রথমে যা অদ্ভুত তা হ'ল প্যারামিটারটি (__আর &&_আর্গ), কারণ যখন আমি নীচের মত দেখতে ফাংশনটি কল করি তখন,

// main()
Object obj1;
Object obj2 = std::move(obj1);

এটি মূলত সমান

// std::move()
_Ty&& _Arg = Obj1;

তবে আপনি ইতিমধ্যে জানেন যে আপনি কোনও এলভালুকে সরাসরি আরভ্যালু রেফারেন্সের সাথে সংযুক্ত করতে পারবেন না, যা আমাকে এইরকম হওয়া উচিত বলে মনে করে।

_Ty&& _Arg = (Object&&)obj1;

তবে এটি অযৌক্তিক কারণ std :: পদক্ষেপ () অবশ্যই সমস্ত মানের জন্য কাজ করে work

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

template<class _Ty>
struct _Remove_reference
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&>
{   // remove reference
    typedef _Ty _Type;
};

template<class _Ty>
struct _Remove_reference<_Ty&&>
{   // remove rvalue reference
    typedef _Ty _Type;
};

দুর্ভাগ্যক্রমে এটি এখনও বিভ্রান্তিকর এবং আমি এটি পাই না।

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


31
@ নিকোলবোলস বিপরীতে, প্রশ্ন নিজেই দেখায় যে ওপি তাদের এই বিবৃতিতে নিজেকে হীন করে দিচ্ছে। এটি ঠিক ওপিকের বেসিক সিনট্যাক্স দক্ষতার উপলব্ধি যা তাদের এমনকি প্রশ্ন উত্থাপন করতে সহায়তা করে।
কাইল স্ট্র্যান্ড

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

আমি মনে করি যে এখানে moveকীভাবে এটি কার্যকর করা হয় তার চেয়ে কীভাবে কাজ করে তা বুঝতে আমি এখানে এসেছি । আমি এই ব্যাখ্যাটি সত্যই দরকারী বলে মনে করি: pagefault.blog/2018/03/01/…
আন্তন ডানিয়েকো

উত্তর:


170

আমরা সরানো ফাংশন দিয়ে শুরু করি (যা আমি কিছুটা পরিষ্কার করেছি):

template <typename T>
typename remove_reference<T>::type&& move(T&& arg)
{
  return static_cast<typename remove_reference<T>::type&&>(arg);
}

আসুন সহজ অংশটি দিয়ে শুরু করা যাক - যখন ফাংশনকে মূল্যের সাথে ডাকা হয়:

Object a = std::move(Object());
// Object() is temporary, which is prvalue

এবং আমাদের moveটেমপ্লেটটি নীচে ইনস্ট্যান্ট হয়ে যায়:

// move with [T = Object]:
remove_reference<Object>::type&& move(Object&& arg)
{
  return static_cast<remove_reference<Object>::type&&>(arg);
}

যেহেতু remove_referenceধর্মান্তরিত T&করার Tবা T&&করার T, এবং Objectরেফারেন্স নয়, আমাদের চূড়ান্ত ফাংশন:

Object&& move(Object&& arg)
{
  return static_cast<Object&&>(arg);
}

এখন, আপনি ভাবতে পারেন: আমাদের এমনকি অভিনেতার প্রয়োজন? উত্তর: হ্যাঁ, আমরা করি। কারণটি সহজ; নামে rvalue রেফারেন্স হয় lvalue হিসাবে গণ্য (এবং rvalue রেফারেন্স করার lvalue থেকে অন্তর্নিহিত রূপান্তর মান দ্বারা নিষিদ্ধ করা হয়)।


আমরা যখন moveল্যাভ্যু দিয়ে কল করি তখন কী হয় :

Object a; // a is lvalue
Object b = std::move(a);

এবং সম্পর্কিত moveতাত্ক্ষণিক:

// move with [T = Object&]
remove_reference<Object&>::type&& move(Object& && arg)
{
  return static_cast<remove_reference<Object&>::type&&>(arg);
}

আবার remove_referenceরূপান্তরিত Object&হয় Objectএবং আমরা পাই:

Object&& move(Object& && arg)
{
  return static_cast<Object&&>(arg);
}

এখন আমরা কৌতুকপূর্ণ অংশে Object& &&পৌঁছেছি : এমনকি এর অর্থ কী এবং এটি কীভাবে দামকে আবদ্ধ করতে পারে?

নিখুঁত ফরোয়ার্ডিংয়ের অনুমতি দেওয়ার জন্য, সি ++ 11 স্ট্যান্ডার্ডটি রেফারেন্স ভেঙে যাওয়ার জন্য বিশেষ নিয়ম সরবরাহ করে, যা নিম্নরূপ:

Object &  &  = Object &
Object &  && = Object &
Object && &  = Object &
Object && && = Object &&

যেমন আপনি দেখতে পাচ্ছেন, এই বিধিগুলির অধীনে Object& &&আসলে এর অর্থ Object&হ'ল প্লেইন ল্যাভেলু রেফারেন্স যা বাধ্যতামূলক লভ্যালুগুলিকে অনুমতি দেয়।

চূড়ান্ত ফাংশনটি হ'ল:

Object&& move(Object& arg)
{
  return static_cast<Object&&>(arg);
}

যা মূল্যবৃদ্ধির সাথে পূর্ববর্তী ইনস্ট্যান্টেশনের মতো নয় - তারা উভয়ই তার যুক্তিটিকে মূল্যায়ন রেফারেন্সের পক্ষে ফেলেছে এবং তারপরে এটি ফিরিয়ে দেয়। পার্থক্যটি হ'ল প্রথম ইনস্ট্যান্টেশনটি কেবলমাত্র মূল্যবোধের সাথে ব্যবহার করা যেতে পারে, যখন দ্বিতীয়টি ল্যাভেলুয়েসের সাথে কাজ করে।


আমাদের আরও কিছু কেন প্রয়োজন তা remove_referenceবোঝাতে, আসুন এই ফাংশনটি চেষ্টা করুন

template <typename T>
T&& wanna_be_move(T&& arg)
{
  return static_cast<T&&>(arg);
}

এবং এটি ল্যাভেলু দিয়ে ইনস্ট্যান্ট করুন।

// wanna_be_move [with T = Object&]
Object& && wanna_be_move(Object& && arg)
{
  return static_cast<Object& &&>(arg);
}

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

Object& wanna_be_move(Object& arg)
{
  return static_cast<Object&>(arg);
}

3
চমৎকার উত্তর. যদিও আমি বুঝতে পেরেছি যে একটি মূল্যমানের জন্য এটি মূল্যায়ন Tকরা ভাল ধারণা Object&, তবে আমি জানতাম না যে এটি সত্যিই করা হয়েছে। আমি এই ক্ষেত্রেও Tমূল্যায়ন করার প্রত্যাশা Objectকরতাম, কারণ আমি ভেবেছিলাম যে এটি মোড়ক রেফারেন্স প্রবর্তনের কারণ এবং std::refএটি ছিল না বা ছিল না।
খ্রিস্টান রাউ

2
template <typename T> void f(T arg)(উইকিপিডিয়া নিবন্ধে যা রয়েছে) এবং এর মধ্যে পার্থক্য রয়েছে template <typename T> void f(T& arg)। প্রথমটি মানটির সংশোধন করে (এবং আপনি যদি রেফারেন্সটি পাস করতে চান তবে আপনাকে এটিতে আবৃত রাখতে হবে std::ref), দ্বিতীয়টি সর্বদা রেফারেন্সের সমাধান করে। দুঃখের বিষয়, টেমপ্লেট আর্গুমেন্ট ছাড়ের নিয়মগুলি জটিল, তাই কেন T&&পুনরায় সংশ্লেষ করা Object& &&হয় তা আমি সঠিক যুক্তি সরবরাহ করতে পারি না (তবে এটি সত্যই ঘটে)।
ভিটাস

1
কিন্তু, এই প্রত্যক্ষ পদ্ধতির কাজ না করার কোনও কারণ আছে কি? template <typename T> T&& also_wanna_be_move(T& arg) { return static_cast<T&&>(arg); }
গ্রেগগো

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

3
@ এমজিউকা: আপনি যদি std::moveকেবলমাত্র মূল্যবোধগুলিতে মূল্যায়ন করতে চান তবে হ্যাঁ, T&ঠিক আছে। এই কৌশলটি নমনীয়তার জন্য বেশিরভাগ ক্ষেত্রেই করা হয়: আপনি std::moveসবকিছুতে কল করতে পারেন (মূল্য অন্তর্ভুক্ত) এবং মূল্য ফিরে পেতে পারেন।
ভিটাস

4

_Ty একটি টেম্পলেট প্যারামিটার এবং এই পরিস্থিতিতে

Object obj1;
Object obj2 = std::move(obj1);

_আপনি "অবজেক্ট এবং" টাইপ করেন

যে কারণে _ সরানো_প্রয়োজন প্রয়োজন।

এটা আরও ভালো লাগবে

typedef Object& ObjectRef;
Object obj1;
ObjectRef&& obj1_ref = obj1;
Object&& obj2 = (Object&&)obj1_ref;

আমরা যদি রেফারেন্সটি সরিয়ে না ফেলে থাকি তবে এটি আমাদের মতো করার মতো হবে

Object&& obj2 = (ObjectRef&&)obj1_ref;

তবে অবজেক্টআরফ এবং অ্যান্ডজেক্টে কমিয়ে দেয়, যা আমরা আপত্তি 2 তে বাঁধতে পারি না।

যেভাবে এটি এইভাবে হ্রাস করে তা হ'ল নিখুঁত ফরওয়ার্ডিং সমর্থন করা। এই কাগজ দেখুন ।


এটি কেন _Remove_reference_প্রয়োজনীয় তা সম্পর্কে সমস্ত কিছু ব্যাখ্যা করে না । উদাহরণস্বরূপ, আপনার যদি Object&টাইপডেফ হিসাবে থাকে এবং আপনি এটির একটি রেফারেন্স নেন তবে আপনি এখনও পান Object&। কেন এটি && এর সাথে কাজ করে না? সেখানে হয় যে একটি উত্তর, এবং এটি নিখুঁত ফরওয়ার্ডিং কি আছে।
নিকোল বোলাস

2
সত্য। এবং উত্তর খুব আকর্ষণীয়। একটি & এ & এ হ্রাস করা হয়েছে, সুতরাং আমরা যদি (অবজেক্টরিফ এবং&) অবজেক্ট_আরফ ব্যবহার করার চেষ্টা করি, তবে আমরা এক্ষেত্রে অবজেক্ট এবং এর পরিবর্তে পেয়ে যাব।
ভন ক্যাটো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.