অটো && আমাদের কী বলে?


168

আপনি যদি কোড পড়েন

auto&& var = foo();

যেখানে fooকোনো ধরনের মান দ্বারা ফেরার ফাংশন T। তারপরে varপ্রকারের মূল্যের উল্লেখের একটি মূল্যমান T। তবে এটি কী বোঝায় var? এর অর্থ কি, আমাদের সম্পদ চুরি করার অনুমতি রয়েছে var? এমন কোনও যুক্তিসঙ্গত পরিস্থিতি আছে যখন আপনি যখন আপনার একচেটিয়া মালিকানা পেয়েছেন এমন কোনও auto&&কথা ফেরানোর সময় আপনার কোডের পাঠককে আপনার মতো কিছু করার কথা ব্যবহার করা উচিত unique_ptr<>? এবং শ্রেণীর ধরণের T&&যখন উদাহরণস্বরূপ সম্পর্কে কি T?

আমি কেবল বুঝতে চাই, যদি auto&&টেম্পলেট প্রোগ্রামিংয়ের তুলনায় অন্য কোনও ব্যবহারের মামলা থাকে; স্কট মায়ার্স দ্বারা সর্বজনীন রেফারেন্স এই নিবন্ধের উদাহরণগুলিতে আলোচিত বিষয়গুলির মতো ।


1
আমি একই জিনিস ভাবছি। আমি বুঝতে পারি কীভাবে টাইপ ছাড়ের কাজ হয় তবে আমি ব্যবহার করার সময় আমার কোড কী বলছেauto&& ? আমি লুপের জন্য একটি পরিসীমা-ভিত্তিক auto&&উদাহরণ হিসাবে ব্যবহারের জন্য কেন বিস্তৃত হয় তা দেখার চিন্তা করেছিলাম , তবে এটির সাথে এটি আর পায়নি। সম্ভবত যে উত্তর দেয় সে এটি ব্যাখ্যা করতে পারে।
জোসেফ ম্যানসফিল্ড

1
এটি কি আইনী? আমি বোঝাতে চাইছি যে টি এর ইনস্ট্যান্স fooরিটার্নের পরে অবিলম্বে ধ্বংস হয়ে যায় , একটি মূল্যবোধের রেফ সংরক্ষণ করে এটি ইউবি থেকে নে বলে মনে হয়।

1
@ আলেগুনা এটি পুরোপুরি আইনী। আমি স্থানীয় ভেরিয়েবলের কোনও রেফারেন্স বা পয়েন্টারটি ফিরিয়ে দিতে চাই না, তবে একটি মান। ফাংশন fooমত উদাহরণ চেহারার জন্য পারে: int foo(){return 1;}
এমডভিড

9
অলেগুনার রেফারেন্সগুলি অস্থায়ীগুলির জন্য রেফারেন্সগুলি সি ++ 98 এর মতোই আজীবন বর্ধন সম্পাদন করে।
ইকামত্মর

5
@ আলেগুনার আজীবন এক্সটেনশানটি কেবল স্থানীয় অস্থায়ী সাথে কাজ করে, ফাংশনগুলি উল্লেখ করে ফিরে আসে না। দেখুন stackoverflow.com/a/2784304/567292
ecatmur

উত্তর:


232

auto&& var = <initializer>আপনি যা বলছেন তা ব্যবহার করে : আমি যে কোনও প্রাথমিককরণ গ্রহণ করবো তা নির্বিশেষে এটি লভ্যালু বা মূল্যমানের অভিব্যক্তি এবং আমি এর দৃ const়তা রক্ষা করব । এটি সাধারণত ফরওয়ার্ডিংয়ের জন্য ব্যবহৃত হয় (সাধারণত সাথে T&&)। এই কাজ করার কারণটি হ'ল একটি "সার্বজনীন রেফারেন্স", auto&&বা T&&যে কোনও কিছুর সাথে আবদ্ধ হবে ।

আপনি বলতে পারেন, ভাল কেন কেবল একটি ব্যবহার করবেন না const auto&কারণ এটি কোনও কিছুর সাথেও আবদ্ধ হবে ? constরেফারেন্স ব্যবহার করে সমস্যা হচ্ছে এটি const! আপনি পরে এটি কোনও নিরপেক্ষ রেফারেন্সের সাথে আবদ্ধ করতে পারবেন না বা চিহ্নিত নয় এমন কোনও সদস্য ফাংশন প্রার্থনা করতে পারবেন না const

উদাহরণস্বরূপ, কল্পনা করুন যে আপনি একটি পেতে চান std::vector, এটির প্রথম উপাদানটিতে একটি পুনরুক্তিকারককে নিয়ে যান এবং সেই পুনরুক্তিকারীটির দ্বারা নির্দেশিত মানটি কোনও উপায়ে সংশোধন করুন:

auto&& vec = some_expression_that_may_be_rvalue_or_lvalue;
auto i = std::begin(vec);
(*i)++;

এই কোডটি প্রাথমিক সূচকটি নির্বিশেষে ঠিক সূক্ষ্ম সংকলন করবে। auto&&নিম্নলিখিত উপায়ে ব্যর্থ বিকল্পগুলি :

auto         => will copy the vector, but we wanted a reference
auto&        => will only bind to modifiable lvalues
const auto&  => will bind to anything but make it const, giving us const_iterator
const auto&& => will bind only to rvalues

সুতরাং এই জন্য, auto&&পুরোপুরি কাজ করে! এর auto&&মতো ব্যবহারের উদাহরণ একটি ব্যাপ্তি-ভিত্তিক forলুপে রয়েছে। দেখুন আমার অন্যান্য প্রশ্ন আরো বিস্তারিত জানার জন্য।

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

auto&& var = some_expression_that_may_be_rvalue_or_lvalue;
// var was initialized with either an lvalue or rvalue, but var itself
// is an lvalue because named rvalues are lvalues
use_it_elsewhere(std::forward<decltype(var)>(var));

এর ফলে use_it_elsewhereকর্মক্ষমতা (এড়ানো কপি) অনুরোধে জন্য তার সাহস আউট চেরা যখন মূল সূচনাকারী একটি সংশোধনযোগ্য rvalue ছিল।

এর অর্থ কী বা আমরা যখন থেকে সম্পদ চুরি করতে পারি তার অর্থ কী var? ভাল যেহেতু যে auto&&কোনও কিছুর সাথে আবদ্ধ হবে, আমরা সম্ভবত varনিজের সাহসিকতাগুলি ছিনিয়ে নেওয়ার চেষ্টা করতে পারি না - এটি খুব ভাল দামের বা এমনকি কনস্টও হতে পারে। তবে আমরা std::forwardএটি অন্যান্য ক্রিয়াকলাপগুলিতে করতে পারি যা এর অভ্যন্তরের অভ্যন্তরে সম্পূর্ণরূপে সর্বনাশ করতে পারে। varএটি করার সাথে সাথে আমাদের একটি অবৈধ অবস্থায় থাকা উচিত an

এখন আসুন auto&& var = foo();আপনার প্রশ্নে যেমনটি দেওয়া হয়েছে, যেখানে foo Tমান অনুসারে একটি ফেরত দেয় সেই ক্ষেত্রে এটি প্রয়োগ করুন । এই ক্ষেত্রে আমরা নিশ্চিতভাবে জানি যে প্রকারটি varহ্রাস করা হবে T&&। যেহেতু আমরা নিশ্চিতভাবে জানি যে এটি একটি মূল্যবান, তাই std::forwardএর সংস্থানগুলি চুরি করার জন্য আমাদের অনুমতি লাগবে না । এই নির্দিষ্ট ক্ষেত্রে, মূল্য অনুসারে রিটার্ন জেনেfoo পাঠকের কেবল এটি পড়তে হবে: আমি যে অস্থায়ী থেকে ফিরে এসেছি তার একটি মূল্যবান রেফারেন্স নিচ্ছি foo, তাই আমি খুশি হয়ে এ থেকে সরে যেতে পারি।


সংযোজন হিসাবে, আমি মনে করি এটি উল্লেখ করার উপযুক্ত যখন some_expression_that_may_be_rvalue_or_lvalueএকটি "ওয়েল আপনার কোডটি পরিবর্তিত হতে পারে" পরিস্থিতি ব্যতীত অন্য মত প্রকাশ হতে পারে। সুতরাং এখানে একটি স্বতন্ত্র উদাহরণ:

std::vector<int> global_vec{1, 2, 3, 4};

template <typename T>
T get_vector()
{
  return global_vec;
}

template <typename T>
void foo()
{
  auto&& vec = get_vector<T>();
  auto i = std::begin(vec);
  (*i)++;
  std::cout << vec[0] << std::endl;
}

এখানে, get_vector<T>()সেই মনোরম অভিব্যক্তি যা জেনেরিক ধরণের উপর নির্ভর করে লভালু বা মূল্যমান হতে পারে T। আমরা get_vectorটেম্পলেট প্যারামিটারের মাধ্যমে মূলত রিটার্নের ধরণটি পরিবর্তন করি foo

আমরা যখন কল foo<std::vector<int>>, get_vectorফিরে আসবে global_vecমান, যা একটি rvalue অভিব্যক্তি দেয় দ্বারা। অন্যথা, যখন আমরা কল foo<std::vector<int>&>, get_vectorফিরে আসবে global_vec, রেফারেন্স দ্বারা একটি lvalue অভিব্যক্তি ফলে।

আমরা যদি:

foo<std::vector<int>>();
std::cout << global_vec[0] << std::endl;
foo<std::vector<int>&>();
std::cout << global_vec[0] << std::endl;

আমরা প্রত্যাশিত হিসাবে নিম্নলিখিত আউটপুট পেতে:

2
1
2
2

আপনি পরিবর্তন করতে হলে auto&&কোন কোডে auto, auto&, const auto&, অথবা const auto&&তারপর আমরা ফলাফলের আমরা চাই পাবেন না।


আপনার auto&&রেফারেন্সটি কোনও মূল্যবান বা মূল্যবান এক্সপ্রেশন দিয়ে আরম্ভ করা হয়েছে তার উপর ভিত্তি করে প্রোগ্রাম যুক্তি পরিবর্তন করার বিকল্প উপায় হ'ল ধরণের বৈশিষ্ট্য ব্যবহার করা:

if (std::is_lvalue_reference<decltype(var)>::value) {
  // var was initialised with an lvalue expression
} else if (std::is_rvalue_reference<decltype(var)>::value) {
  // var was initialised with an rvalue expression
}

2
আমরা কেবল T vec = get_vector<T>();ফাংশন ফু এর ভিতরে বলতে পারি না ? বা আমি কি এটিকে বেআইনী স্তরে সরলীকরণ করছি :)
অস্টেরিস্ক

@ এস্টারিস্ক নো বেকোজ টি ভিসিকে কেবল স্টাডি :: ভেক্টর <ইন্টি>> এর ক্ষেত্রে ললিউয়ে অর্পণ করা যেতে পারে এবং যদি টি স্ট্যান্ডার্ড :: ভেক্টর <int> হয় তবে আমরা মান অনুসারে কলটি ব্যবহার করব যা অকার্যকর
কাপিল

1
অটো এবং আমাকে একই ফলাফল দেয়। আমি এমএসভিসি 2015 ব্যবহার করছি And এবং জিসিসি একটি ত্রুটি তৈরি করে।
সের্গে পোডোব্রি

এখানে আমি এমএসভিসি 2015 ব্যবহার করছি, অটো এবং অটো ও& এর মতো ফলাফল দেয়।
কেহে CAI

ইন্ট আই কেন; স্বতঃ && j = i; অনুমোদিত কিন্তু int i; int && j = i; এটি না ?
সপ্তমসন 84

14

প্রথমত, আমি সর্বজনীন রেফারেন্সগুলির জন্য টেমপ্লেট আর্গুমেন্ট কর্তন কীভাবে কাজ করে তার ধাপে ধাপে ব্যাখ্যাটির জন্য আমার এই উত্তরটি সাইড-রিড হিসাবে পড়ার পরামর্শ দিচ্ছি ।

এর অর্থ কি, আমাদের সম্পদ চুরি করার অনুমতি রয়েছে var?

অগত্যা। foo()হঠাৎ করেই যদি কোনও রেফারেন্স ফিরে আসে, বা আপনি কলটি পরিবর্তন করেছেন তবে ব্যবহারটি আপডেট করতে ভুলে গেছেন var? অথবা আপনি যদি জেনেরিক কোডটিতে থাকেন এবং foo()আপনার পরামিতিগুলির উপর নির্ভর করে ফেরতের ধরণটি বদলে যেতে পারে?

চিন্তা করুন auto&&যেমন ঠিক একই হতে T&&মধ্যে template<class T> void f(T&& v);, কারণ এটি এর (প্রায় ) ঠিক যে। যখন আপনাকে সেগুলি পাশ দিয়ে যাওয়ার বা কোনও উপায়ে ব্যবহার করার দরকার হয় তখন আপনি কার্যগুলিতে সর্বজনীন রেফারেন্সগুলি দিয়ে কী করবেন? আপনি std::forward<T>(v)মূল মান বিভাগটি ফিরে পেতে ব্যবহার করুন । আপনার ফাংশনে যাওয়ার আগে যদি এটি কোনও মূল্যমান হয় তবে এটি পাস করার পরে লভ্যালু থেকে যায় std::forward। যদি এটি কোনও মূল্য ছিল, তবে এটি আবার একটি মূল্যবান হয়ে উঠবে (মনে রাখবেন, নামযুক্ত মূল্যবোধের রেফারেন্সটি একটি মূল্য)।

সুতরাং, আপনি কীভাবে varজেনেরিক ফ্যাশনে সঠিকভাবে ব্যবহার করবেন ? ব্যবহার std::forward<decltype(var)>(var)। এটি std::forward<T>(v)উপরের ফাংশন টেম্পলেটের মতো একই কাজ করবে will যদি varএকটি হয় T&&, আপনি একটি rvalue ফিরে পাবেন, এবং যদি তা না হয় T&, আপনি একটি lvalue ফিরে পাবেন।

সুতরাং, ফিরে আসুন বিষয়গুলি : auto&& v = f();এবং std::forward<decltype(v)>(v)একটি কোডবেসে আমাদের কী বলে? তারা আমাদের জানায় যে vঅধিগ্রহণ করা হবে এবং সবচেয়ে কার্যকর উপায়ে পাস করা হবে। তবে মনে রাখবেন যে এইরকম চলক ফরোয়ার্ড করার পরে এটি সম্ভব হয়েছে যে এটি স্থানান্তরিত হয়ে গেছে, সুতরাং এটি পুনরায় সেট না করে এটি আরও ভুল ব্যবহার করতে চাই।

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


autoএতদূর বিভিন্ন যে হয় auto v = {1,2,3};করতে হবে vএকটি std::initializer_list, যখন f({1,2,3})সিদ্ধান্তগ্রহণ ব্যর্থতা হবে।


আপনার উত্তরের প্রথম অংশে: আমার অর্থ হ'ল যদি foo()কোনও মান-প্রকারটি ফেরত দেয় Tতবে var(এই অভিব্যক্তিটি) একটি মূল্য হবে এবং এর ধরণের (এই অভিব্যক্তির) একটি যথাযথ রেফারেন্স হবে T(অর্থাত T&&)।
এমডভিড

@ এমডভিড: বোধ করে, প্রথম অংশটি সরিয়ে দিয়েছে।
Xeo

3

এমন কোন ধরণের বিবেচনা করুন Tযার একটি মুভ কনস্ট্রাক্টর রয়েছে এবং ধরে নিন

T t( foo() );

যে সরানো কনস্ট্রাক্টর ব্যবহার করে।

এখন, এর থেকে রিটার্ন ক্যাপচার জন্য একটি মধ্যবর্তী রেফারেন্স ব্যবহার করুন foo:

auto const &ref = foo();

এটি মুভ কনস্ট্রাক্টর ব্যবহারের বিধি নিষেধ করে, সুতরাং রিটার্নের মানটি সরানোর পরিবর্তে অনুলিপি করতে হবে (এমনকি আমরা যদি std::moveএখানে ব্যবহার করি তবে আমরা প্রকৃতপক্ষে কনস্ট রেফের মধ্য দিয়ে যেতে পারি না)

T t(std::move(ref));   // invokes T::T(T const&)

তবে, আমরা যদি ব্যবহার করি

auto &&rvref = foo();
// ...
T t(std::move(rvref)); // invokes T::T(T &&)

সরানো কনস্ট্রাক্টর এখনও উপলব্ধ।


এবং আপনার অন্যান্য প্রশ্নের সমাধান করতে:

... আপনার কোডের পাঠককে কিছু বলার জন্য যখন অটো && ব্যবহার করা উচিত তখন কি কোনও যুক্তিসঙ্গত পরিস্থিতি রয়েছে ...

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

... আপনি যখন অনন্য মালিকানা পেয়েছেন তখন কোনও অনন্য_পিটার <> ফিরিয়ে দেওয়ার সময় আপনি যেমন করেন ...

যখন কোনও ফাংশন টেমপ্লেট প্রকারের একটি আর্গুমেন্ট নেয় T&&, তখন এটি বলছে যে এটি আপনাকে যে জিনিসটি দিয়েছিল তা সরিয়ে ফেলতে পারে exp unique_ptrস্পষ্টভাবে প্রত্যাবর্তনকারী কলারের মালিকানা দেয়; গ্রহণ T&&করতে পারে অপসারণ আহ্বানকারী থেকে মালিকানা (যদি একটি পদক্ষেপ ctor বিদ্যমান, ইত্যাদি)।


2
আমি নিশ্চিত নই যে আপনার দ্বিতীয় উদাহরণটি বৈধ কিনা। সরানো কন্সট্রাক্টরের অনুরোধ করার জন্য আপনার কি নিখুঁত ফরোয়ার্ডিংয়ের দরকার নেই?

3
এটা ভুল. উভয় ক্ষেত্রেই অনুলিপি নির্মাণকারীকে ডাকা হয়, যেহেতু refএবং rvrefউভয়ই মূল্যবান। আপনি যদি মুভ কনস্ট্রাক্টর চান তবে আপনাকে লিখতে হবে T t(std::move(rvref))
এমডভিড

আপনি আপনার প্রথম উদাহরণে const সুত্র কিছু বলতে চাইছেন: auto const &?
পাইট্রনিক্স

@ আলেগুনা - আপনি এবং এমডাব্লু ঠিক বলেছেন, ধন্যবাদ আমি আমার উত্তর স্থির করেছি।
বেহুদা

1
@ ইউসেস আপনি ঠিক বলেছেন তবে এটি আমার ক্রমের উত্তর দেয় না। আপনি কখন ব্যবহার করবেন auto&&এবং আপনি আপনার কোডটি পাঠককে auto&&কী ব্যবহার করবেন ?
এমডভিড

-3

auto &&সিনট্যাক্স সি ++ 11 দুটি নতুন বৈশিষ্ট্য ব্যবহার করে:

  1. autoঅংশ টাইপ প্রসঙ্গ (এই ক্ষেত্রে ফেরত মান) উপর ভিত্তি করে অনুমান কম্পাইলার করতে দেয়। এই যে কোনো রেফারেন্স যোগ্যতা (এরফলে আপনি চান তা নির্দিষ্ট করতে সক্ষম হবেন ছাড়া হয় T, T &বা T &&একটি অনুমিত টাইপ জন্য T)।

  2. &&নতুন পদক্ষেপ শব্দার্থবিদ্যা হয়। একটি প্রকার সমর্থনকারী মুভ শব্দার্থক একটি কন্সট্রাক্টর প্রয়োগ T(T && other)করে যা সামগ্রীতে নতুন ধরনের সামগ্রীতে সরিয়ে দেয়। এটি কোনও বস্তুকে গভীর অনুলিপি সম্পাদনের পরিবর্তে অভ্যন্তরীণ উপস্থাপনের অদলবদল করতে দেয়।

এটি আপনাকে এর মতো কিছু করতে দেয়:

std::vector<std::string> foo();

তাই:

auto var = foo();

প্রত্যাশিত ভেক্টরের একটি অনুলিপি (ব্যয়বহুল) সম্পাদন করবে তবে:

auto &&var = foo();

ভেক্টরের অভ্যন্তরীণ উপস্থাপনা (ভেক্টর কাছ থেকে fooএবং খালি ভেক্টর থেকে var) অদলবদল করবে , তাই দ্রুত হবে।

এটি নতুন ফর-লুপ সিনট্যাক্সে ব্যবহৃত হয়:

for (auto &item : foo())
    std::cout << item << std::endl;

যেখানে ফর-লুপটি auto &&রিটার্ন মানটি ধরে রাখে fooএবং itemপ্রতিটি মানের একটি রেফারেন্স foo


এটি ভুল। auto&&কিছু সরবে না, এটি কেবল একটি রেফারেন্স তৈরি করবে। এটি কোনও মূল্য বা মূল্যের রেফারেন্স এটি শুরু করতে ব্যবহৃত অভিব্যক্তির উপর নির্ভর করে।
জোসেফ ম্যানসফিল্ড

উভয় ক্ষেত্রে মুভ কনস্ট্রাক্টরকে ডাকা হবে, যেহেতু std::vectorএবং std::stringমুভ কনস্ট্রাকটিভেবল। এর ধরণের সাথে এর কোনও যোগসূত্র নেই var
এমডেউইড

1
@ এমডভিড: প্রকৃতপক্ষে, অনুলিপি / মুভ কনস্ট্রাক্টরের কলটি আরভিওর সাথেও পুরোপুরিভাবে সহায়তা করা যেতে পারে।
ম্যাথিউ এম।

@MatthieuM। তুমি ঠিক. তবে আমি মনে করি যে উপরের উদাহরণে, অনুলিপি cnstructor কখনও কল করা হবে না, যেহেতু সবকিছুই মুভ কনস্ট্রাক্টেবল।
এমডভিড

1
@ এমডাব্লিউড: আমার বক্তব্যটি ছিল যে এমনকি মুভ কনস্ট্রাক্টরকেও আলাদা করা যেতে পারে। এলিজেন ট্রাম্পগুলি সরানো (এটি সস্তা)।
ম্যাথিউ এম।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.