`Std :: move` এর নাম` std :: move` কেন রাখা হয়েছে?


128

সি ++ 11 std::move(x)ফাংশনটি আসলে কিছুতেই সরায় না। এটি আর-মানের জন্য একটি কাস্ট। কেন এটি করা হয়েছিল? এটা কি বিভ্রান্তিকর নয়?


বিষয়টিকে আরও খারাপ করার জন্য, ত্রি-যুক্তিটি std::moveআসলে চলে যায় ..
কুবি

এবং সি ++ std::char_traits::move
98/03/11

30
আমার অন্যান্য প্রিয় হ'ল std::remove()যা উপাদানগুলি সরিয়ে দেয় না: আপনাকে এখনও erase()ধারক থেকে সেই উপাদানগুলি সরাতে কল করতে হবে। সুতরাং moveসরানো removeহয় না, সরান না। আমি নাম বাছাই করা যেত mark_movable()জন্য move
আলী

4
@ অলিও আমি mark_movable()বিভ্রান্তিকর দেখতে পেলাম । এটি প্রস্তাব দেয় যে সেখানে দীর্ঘস্থায়ী পার্শ্ব প্রতিক্রিয়া রয়েছে যেখানে আসলে কিছুই নেই।
ফিনউইউ

উত্তর:


177

এটা যে সঠিক std::move(x)আরো নির্দিষ্টভাবে একটি করুন - হয় rvalue মাত্র একটি ঢালাই xvalue , একটি উল্টোদিকে prvalue । এবং এটিও সত্য যে নামকরণ করা কাস্ট moveকখনও কখনও মানুষকে বিভ্রান্ত করে। তবে এই নামকরণের উদ্দেশ্যটি বিভ্রান্ত করা নয়, বরং আপনার কোডটি আরও পাঠযোগ্য।

ইতিহাস 2002 সালে মূল পদক্ষেপ প্রস্তাব থেকেmove ফিরে । এই কাগজটি প্রথমে মূলতার রেফারেন্সের সাথে পরিচয় করিয়ে দেয় এবং তারপরে আরও কার্যকরভাবে কীভাবে লিখতে হয় তা দেখায় :std::swap

template <class T>
void
swap(T& a, T& b)
{
    T tmp(static_cast<T&&>(a));
    a = static_cast<T&&>(b);
    b = static_cast<T&&>(tmp);
}

এক স্মরণ যে ইতিহাসে এই সময়ে, একমাত্র জিনিস যে "হয়েছে &&" পারে সম্ভবত গড় ছিল যৌক্তিক এবং । মূল্যমানের রেফারেন্সগুলির সাথে কেউ পরিচিত ছিল না, বা কোনও মূল্যকে কোনও মূল্য দেওয়ার জন্য (যেমনটি কোনও অনুলিপি তৈরি করার সময় নয় static_cast<T>(t)) জড়িত সম্পর্কেও জানত না । সুতরাং এই কোডটির পাঠকরা স্বাভাবিকভাবেই ভাবেন:

আমি জানি কীভাবে swapকাজ করার কথা রয়েছে (অস্থায়ীভাবে অনুলিপি করুন এবং তারপরে মানগুলি বিনিময় করুন) তবে এই কুৎসিত জাতগুলির উদ্দেশ্য কী ?!

এটিও নোট করুন যে swapসব ধরণের ক্রম-পরিবর্তন-সংশোধনকারী অ্যালগরিদমগুলির জন্য সত্যই একটি স্ট্যান্ড-ইন। এই আলোচনা অনেক বেশি , অনেক বড় swap

তারপরে প্রস্তাবটি সিনট্যাক্স চিনির সাথে পরিচয় করিয়ে দিয়েছিল যা static_cast<T&&>আরও বেশি পাঠযোগ্য কিছু দিয়ে প্রতিস্থাপন করে যা সুনির্দিষ্ট কোনটি বোঝায় না , বরং কেন :

template <class T>
void
swap(T& a, T& b)
{
    T tmp(move(a));
    a = move(b);
    b = move(tmp);
}

অর্থাত moveমাত্র বাক্য গঠন চিনি হয় static_cast<T&&>, এবং এখন কোডে কেন কাস্ট আছে যেমন বেশ ইঙ্গিতপূর্ণ হল: পদক্ষেপ শব্দার্থবিদ্যা সক্ষম করুন!

একজনকে অবশ্যই বুঝতে হবে যে ইতিহাসের প্রেক্ষাপটে, এই মুহুর্তে খুব কম লোকই মূল্যের এবং সরানো শব্দার্থবিজ্ঞানের মধ্যে অন্তরঙ্গ সংযোগটি বুঝতে পেরেছিল (যদিও কাগজটি সেটিকেও ব্যাখ্যা করার চেষ্টা করেছে):

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

যদি সেই সময়ে swapপরিবর্তে এটি উপস্থাপন করা হত:

template <class T>
void
swap(T& a, T& b)
{
    T tmp(cast_to_rvalue(a));
    a = cast_to_rvalue(b);
    b = cast_to_rvalue(tmp);
}

তাহলে লোকেরা সেদিকে তাকাবে এবং বলে:

তবে আপনি কেন মূল্যায়ন করছেন?


মূলকথা:

যেমনটি ছিল, ব্যবহার করে move, কেউ কখনও জিজ্ঞাসা করেনি:

তবে আপনি কেন নড়াচড়া করছেন?


বছরগুলি চলতে থাকায় এবং প্রস্তাবটি পরিমার্জনিত হওয়ার সাথে সাথে আজ আমাদের মূল্যমানের বিভাগগুলিতে মূল্যমান এবং মূল্যমানের ধারণাগুলি পরিমার্জন করা হয়েছিল :

বর্গীকরণ সূত্র

(নির্লজ্জভাবে চিত্রটি নির্লজ্জভাবে চুরি করা হয়েছে )

তাই আজ, আমরা চেয়েছিলাম যদি swapঅবিকল বলতে কি এরকম হয়, পরিবর্তে কেন , এটি আরো মত হওয়া উচিত:

template <class T>
void
swap(T& a, T& b)
{
    T tmp(set_value_category_to_xvalue(a));
    a = set_value_category_to_xvalue(b);
    b = set_value_category_to_xvalue(tmp);
}

এবং প্রত্যেকের নিজেরাই যে প্রশ্নটি জিজ্ঞাসা করা উচিত তা হ'ল উপরের কোডটি কম বা কম পাঠযোগ্য:

template <class T>
void
swap(T& a, T& b)
{
    T tmp(move(a));
    a = move(b);
    b = move(tmp);
}

বা এমনকি মূল:

template <class T>
void
swap(T& a, T& b)
{
    T tmp(static_cast<T&&>(a));
    a = static_cast<T&&>(b);
    b = static_cast<T&&>(tmp);
}

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

অধিকন্তু, যদি কোনও প্রোগ্রামার অন্য নামে এই কার্যকারিতাটি চান, তবে এই কার্যকারিতাটিতে std::moveকোনও একচেটিয়া রাখেন না এবং এর প্রয়োগে কোনও বহনযোগ্য ভাষা জাদু নেই। উদাহরণস্বরূপ যদি কেউ কোড করতে চায় set_value_category_to_xvalueএবং পরিবর্তে এটি ব্যবহার করে তবে এটি করা তুচ্ছ is

template <class T>
inline
constexpr
typename std::remove_reference<T>::type&&
set_value_category_to_xvalue(T&& t) noexcept
{
    return static_cast<typename std::remove_reference<T>::type&&>(t);
}

সি ++ ১৪ এ এটি আরও সংক্ষিপ্ত আকার ধারণ করে:

template <class T>
inline
constexpr
auto&&
set_value_category_to_xvalue(T&& t) noexcept
{
    return static_cast<std::remove_reference_t<T>&&>(t);
}

সুতরাং যদি আপনি এত ঝুঁকে থাকেন static_cast<T&&>তবে আপনার সবচেয়ে ভাল মনে করেন এমনভাবে সাজান এবং সম্ভবত আপনি একটি নতুন সেরা অনুশীলনের বিকাশ করবেন (সি ++ ক্রমাগত বিকশিত হচ্ছে)।

সুতরাং moveজেনারেটেড অবজেক্ট কোডের ক্ষেত্রে কী করবেন?

এটি বিবেচনা করুন test:

void
test(int& i, int& j)
{
    i = j;
}

সংকলিত clang++ -std=c++14 test.cpp -O3 -S, এটি এই অবজেক্ট কোড উত্পাদন করে:

__Z4testRiS_:                           ## @_Z4testRiS_
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    movl    (%rsi), %eax
    movl    %eax, (%rdi)
    popq    %rbp
    retq
    .cfi_endproc

এখন যদি পরীক্ষাটি পরিবর্তন করা হয়:

void
test(int& i, int& j)
{
    i = std::move(j);
}

নেই একেবারে সব সময়ে কোন পরিবর্তন বস্তুর কোডে। এই ফলাফলটিকে সাধারণীকরণ করা যায়: তুচ্ছভাবে চলমান বস্তুর জন্য, std::moveএর কোনও প্রভাব নেই।

এখন এই উদাহরণটি দেখুন:

struct X
{
    X& operator=(const X&);
};

void
test(X& i, X& j)
{
    i = j;
}

এটি উত্পন্ন করে:

__Z4testR1XS0_:                         ## @_Z4testR1XS0_
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    popq    %rbp
    jmp __ZN1XaSERKS_           ## TAILCALL
    .cfi_endproc

আপনি চালাতে পারেন __ZN1XaSERKS_মাধ্যমে c++filtএটা সৃষ্টি করে: X::operator=(X const&)। এখানে অবাক হওয়ার কিছু নেই। এখন যদি পরীক্ষাটি পরিবর্তন করা হয়:

void
test(X& i, X& j)
{
    i = std::move(j);
}

তারপরে উত্পন্ন অবজেক্ট কোডটিতে এখনও কোনও পরিবর্তন নেই । কোনও মূল্যবোধে std::moveফেলে jদেওয়া ছাড়া আর কিছুই করেনি, এবং তারপরে সেই মূল্যটি Xঅনুলিপিটির অনুলিপি অপারেটরের সাথে আবদ্ধ X

এখন এগুলিতে একটি সরানো নিয়োগ অপারেটর যুক্ত করতে দিন X:

struct X
{
    X& operator=(const X&);
    X& operator=(X&&);
};

এখন অবজেক্ট কোড আছে পরিবর্তন:

__Z4testR1XS0_:                         ## @_Z4testR1XS0_
    .cfi_startproc
## BB#0:
    pushq   %rbp
Ltmp0:
    .cfi_def_cfa_offset 16
Ltmp1:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp2:
    .cfi_def_cfa_register %rbp
    popq    %rbp
    jmp __ZN1XaSEOS_            ## TAILCALL
    .cfi_endproc

চলমান __ZN1XaSEOS_মাধ্যমে c++filtজানায় যে X::operator=(X&&)পরিবর্তে বলা হচ্ছে X::operator=(X const&)

আর এটাই তো আছে std::move! এটি রান সময়ে পুরোপুরি অদৃশ্য হয়ে যায়। এর একমাত্র প্রভাবটি সংকলন-সময়ে হয় যেখানে এটি ওভারলোডের কলটি পরিবর্তিত করতে পারে


7
এখানে সেই গ্রাফের জন্য একটি বিন্দুর উত্স: আমি এটি digraph D { glvalue -> { lvalue; xvalue } rvalue -> { xvalue; prvalue } expression -> { glvalue; rvalue } }জনসাধারণের ভালোর জন্য পুনরায় তৈরি করেছি :) এটিকে এসভিজি হিসাবে এখানে
শে

7
এটি কি এখনও বাইক শেডিংয়ের জন্য উন্মুক্ত? আমি প্রস্তাব দিই allow_move;)
ডায়াপ

2
@dyp আমার প্রিয় এখনও আছে movable
ড্যানিয়েল ফ্রে

6
স্কট মায়ার্স এর নাম পরিবর্তন std::moveকরার পরামর্শ দিয়েছে rvalue_cast: youtube.com/…
নয়ারওয়্যার

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

20

আমাকে কেবল এখানে বি স্ট্রস্ট্রুপের লেখা সি ++ 11 এফএকিউ থেকে একটি উদ্ধৃতিটি ছেড়ে দিন , যা ওপির প্রশ্নের সরাসরি উত্তর:

সরানো (এক্স) এর অর্থ "আপনি এক্সকে মূল্য হিসাবে বিবেচনা করতে পারেন" মুভ () কে রিভাল () বলা হত তবে ভাল হত তবে এখনের () পদক্ষেপটি বছরের পর বছর ধরে ব্যবহৃত হয়ে আসছে।

যাইহোক, আমি সত্যিই FAQ উপভোগ করেছি - এটি পড়ার মতো।


2
অন্য উত্তর থেকে @ হাওয়ার্ডহিন্যান্টের মন্তব্য চুরি করার জন্য: স্ট্রাস্ট্রাপের উত্তরটি সঠিক নয়, কারণ এখন দুটি ধরণের মূল্যবোধ রয়েছে - মূল্য এবং এক্সভালিউস, এবং স্ট্যান্ড :: পদক্ষেপটি সত্যই একটি এক্সভালিউর অভিনেত্রী।
einpoklum
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.