সি ++ এ শব্দার্থিক স্থানান্তরিত করুন - স্থানীয় ভেরিয়েবলগুলির মুভ-রিটার্ন


11

আমার বোধগম্যতা হল যে সি ++ ১১-এ, যখন আপনি কোনও ফাংশন থেকে মান অনুসারে একটি স্থানীয় ভেরিয়েবল ফিরিয়ে দেন, সংকলকটিকে সেই পরিবর্তনশীলটিকে আর-মান রেফারেন্স হিসাবে বিবেচনা করার অনুমতি দেয় এবং ফাংশন থেকে 'চালিত' করে এটি ফিরিয়ে দেয় (যদি আরভিও / এনআরভিও এর পরিবর্তে ঘটে না, অবশ্যই)।

আমার প্রশ্ন, এটি কি বিদ্যমান কোডটি ভাঙতে পারে না?

নিম্নলিখিত কোড বিবেচনা করুন:

#include <iostream>
#include <string>

struct bar
{
  bar(const std::string& str) : _str(str) {}
  bar(const bar&) = delete;
  bar(bar&& other) : _str(std::move(other._str)) {other._str = "Stolen";}
  void print() {std::cout << _str << std::endl;}

  std::string _str;
};

struct foo
{
  foo(bar& b) : _b(b) {}
  ~foo() {_b.print();}

  bar& _b;
};

bar foobar()
{
  bar b("Hello, World!");
  foo f(b);

  return std::move(b);
}

int main()
{
  foobar();
  return EXIT_SUCCESS;
}

আমার ধারণা ছিল যে কোনও স্থানীয় অবজেক্টের ডেস্ট্রাক্টরের পক্ষে অবজেক্টটি সরানো হয়ে যাওয়া বস্তুর রেফারেন্স করা সম্ভব হবে এবং অতএব অপ্রত্যাশিতভাবে একটি 'খালি' অবজেক্টটি দেখুন। আমি এটি পরীক্ষা করার চেষ্টা করেছি (দেখুন http://ideone.com/ZURoeT ), তবে আমি পরিষ্কার std::moveনা করেই 'সঠিক' ফলাফল পেয়েছি foobar()। আমি অনুমান করছি যে এটি এনআরভিওর কারণে হয়েছিল তবে আমি সেটি অক্ষম করার জন্য কোডটি পুনরায় সাজানোর চেষ্টা করিনি।

আমি কি ঠিক করছি যে এই রূপান্তরটি (ক্রিয়াকলাপের বাইরে চলে যাওয়ার কারণ) স্পষ্টভাবে ঘটে এবং বিদ্যমান কোডটি ভেঙে দিতে পারে?

আপডেট এখানে একটি উদাহরণ যা আমি কী সম্পর্কে কথা বলছি তা বোঝায়। নিম্নলিখিত দুটি লিঙ্ক একই কোডের জন্য। http://ideone.com/4GFIRu - সি ++ 03 http://ideone.com/FcL2Xj - সি ++ 11

যদি আপনি আউটপুট দেখুন, এটি ভিন্ন।

সুতরাং, আমি অনুমান করি যে এই প্রশ্নটি এখন পরিণত হয়, মানটিতে অন্তর্নিহিত পদক্ষেপ যুক্ত করার সময় এটিই বিবেচনা করা হয়েছিল এবং এই জাতীয় কোডটি যথেষ্ট বিরল হওয়ায় এই ব্রেকিং পরিবর্তনটি যুক্ত করা ঠিক হবে কিনা তা সিদ্ধান্ত নেওয়া হয়েছিল? আমি আরও ভাবছি যে কোনও সংকলক যদি এরকম ক্ষেত্রে সতর্ক করে দেয় ...


একটি পদক্ষেপ অবশ্যই সর্বদা ধ্বংসাত্মক অবস্থায় ফেলে রাখা উচিত।
জ্যান লিংস

হ্যাঁ, তবে এটি প্রশ্ন নয়। প্রাক-সি ++ 11 কোড ধরে নিতে পারে যে স্থানীয় ভেরিয়েবলের মান সহজেই ফিরে আসার কারণে পরিবর্তিত হবে না, সুতরাং এই অন্তর্নিহিত পদক্ষেপটি অনুমানটি ভেঙে দিতে পারে।
বুউব্যাট

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

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

হ্যাঁ, আমি জানি যে সি ++ 11 কখনও কোনও পুরানো কোড ভাঙার দাবি করেনি, তবে এটি অত্যন্ত সূক্ষ্ম, এবং মিস করা সত্যিই সহজ হবে (কোনও সংকলক ত্রুটি, সতর্কতা,
সেগফোল্টস

উত্তর:


8

স্কট মায়ার্স কমপ্লেং.এল.এল ++ (আগস্ট ২০১০) তে পোস্ট করেছেন এমন একটি সমস্যা সম্পর্কে যেখানে মুখ্য নির্মাণকারীদের অন্তর্নিহিত প্রজন্ম সি ++ 03 শ্রেণীর আক্রমণকারীদের ভেঙে ফেলতে পারে:

struct X
{
  // invariant: v.size() == 5
  X() : v(5) {}

  ~X() { std::cout << v[0] << std::endl; }

private:    
  std::vector<int> v;
};

int main()
{
    std::vector<X> y;
    y.push_back(X()); // X() rvalue: copied in C++03, moved in C++0x
}

এখানে সমস্যাটি হ'ল সি ++ 03 তে Xএকটি আক্রমণকারী ছিল যার vসদস্যের সর্বদা 5 টি উপাদান থাকে। X::~X()সেই আক্রমণকারী হিসাবে গণনা করা হয়েছে, তবে সদ্য-প্রবর্তিত মুভ কনস্ট্রাক্টর সেখান থেকে সরানো হয়েছে v, যার ফলে এর দৈর্ঘ্য শূন্যে সেট করা হয়েছে।

এটি আপনার উদাহরণের সাথে সম্পর্কিত যেহেতু ভাঙা আক্রমণকারীটি কেবলমাত্র X'ডেস্ট্রাক্টর'-এ সনাক্ত করা হয়েছে (যেমন আপনি বলছেন যে কোনও স্থানীয় অবজেক্টের ডেস্ট্রাক্টরের পক্ষে অবজেক্টটি স্পষ্টভাবে সরানো হয়ে যায় এবং তাই অপ্রত্যাশিতভাবে একটি ফাঁকা বস্তু দেখতে পাওয়া যায় ) reference

সি ++ 11 বিদ্যমান কিছু কোড ভঙ্গ করে এবং সরানো কনস্ট্রাক্টরের উপর ভিত্তি করে দরকারী অপ্টিমাইজেশন সরবরাহের মধ্যে ভারসাম্য অর্জন করার চেষ্টা করুন।

কমিটি প্রাথমিকভাবে সিদ্ধান্ত নিয়েছে যে মুভ কনস্ট্রাক্টর এবং মুভ অ্যাসাইনমেন্ট অপারেটরগুলি যখন ব্যবহারকারী সরবরাহ না করে তখন সংকলক দ্বারা উত্পন্ন করা উচিত।

তারপরে সিদ্ধান্ত নিয়েছে যে এটি প্রকৃতপক্ষে অ্যালার্মের কারণ এবং এটি কোড কন্ট্রাক্টরগুলি এবং সরানো অ্যাসাইনমেন্ট অপারেটরদের স্বয়ংক্রিয় প্রজন্মকে এমনভাবে সীমাবদ্ধ করেছিল যে বিদ্যমান কোডটি ভাঙার পক্ষে এটি অসম্ভব হলেও কম, যদিও (যেমন স্পষ্টভাবে সংজ্ঞায়িত ডেস্ট্রাক্টর)।

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

ইন N3174 - সরান অথবা না সরাতে করতে Stroupstrup বলেছেন:

আমি এটিকে একটি পিছনের দিকের সামঞ্জস্যের সমস্যার চেয়ে বরং একটি ভাষা নকশা সমস্যা হিসাবে বিবেচনা করি। পুরানো কোডটি ভাঙ্গা এড়ানো সহজ (উদাহরণস্বরূপ কেবল সি ++ 0x থেকে সরানো অপারেশনগুলি সরিয়ে ফেলুন), তবে আমি সি ++ 0xকে আরও ভাল ভাষা করে দেখছি মুভি অপারেশনগুলি একটি বড় লক্ষ্যকে বিস্তৃত করে যার জন্য এটি কিছু সি + ভাঙার উপযুক্ত হতে পারে for +98 কোড।

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