লুপগুলির জন্য এটি কি সি ++ 11 এর একটি পরিচিত সমস্যা?


89

আসুন কল্পনা করুন আমাদের কিছু সদস্য ফাংশন সহ 3 ডাবল রাখার জন্য একটি কাঠামো রয়েছে:

struct Vector {
  double x, y, z;
  // ...
  Vector &negate() {
    x = -x; y = -y; z = -z;
    return *this;
  }
  Vector &normalize() {
     double s = 1./sqrt(x*x+y*y+z*z);
     x *= s; y *= s; z *= s;
     return *this;
  }
  // ...
};

এটি সরলতার জন্য কিছুটা স্বীকৃত, তবে আমি নিশ্চিত যে আপনি সম্মত হন যে অনুরূপ কোডটি এখানে রয়েছে। পদ্ধতিগুলি আপনাকে সুবিধার্থে চেইন করতে দেয়, উদাহরণস্বরূপ:

Vector v = ...;
v.normalize().negate();

অথবা এমনকি:

Vector v = Vector{1., 2., 3.}.normalize().negate();

এখন যদি আমরা শুরু () এবং শেষ () ফাংশন সরবরাহ করি তবে আমরা আমাদের ভেক্টরকে লুপের জন্য একটি নতুন স্টাইলে ব্যবহার করতে পারি, 3 টি স্থানাঙ্ক x, y এবং z এর উপর লুপ করতে বলতে পারি (আপনি সন্দেহাতীতভাবে আরও "দরকারী" উদাহরণ তৈরি করতে পারবেন না ভেক্টরকে উদাহরণস্বরূপ স্ট্রিং দিয়ে প্রতিস্থাপন করে):

Vector v = ...;
for (double x : v) { ... }

আমরা এমনকি করতে পারেন:

Vector v = ...;
for (double x : v.normalize().negate()) { ... }

এবং আরো:

for (double x : Vector{1., 2., 3.}) { ... }

তবে, নিম্নলিখিতগুলি (এটি আমার কাছে মনে হচ্ছে) নষ্ট হয়েছে:

for (double x : Vector{1., 2., 3.}.normalize()) { ... }

এটি আগের দুটি ব্যবহারের যৌক্তিক সংমিশ্রণের মতো মনে হলেও, আমি মনে করি এই শেষ ব্যবহারটি একটি ঝুঁকির রেফারেন্স তৈরি করে যখন আগের দুটি সম্পূর্ণ সূক্ষ্ম।

  • এটি কি সঠিক এবং ব্যাপকভাবে প্রশংসিত?
  • উপরের কোন অংশটি "খারাপ" অংশ, তা এড়ানো উচিত?
  • লুপটির জন্য পরিসর-ভিত্তিক সংজ্ঞা পরিবর্তনের মাধ্যমে ভাষার উন্নতি হবে যে লুপের সময়কালের জন্য প্রকাশের জন্য তৈরি টেম্পোরারিগুলি বিদ্যমান?

কিছু কারণে আমি এর আগে অনুরূপ একটি খুব অনুরূপ প্রশ্নটি স্মরণ করছি, এটি কী বলা হয়েছিল তা ভুলে গেছেন।
পাব্বি

আমি এটিকে একটি ভাষা ত্রুটি হিসাবে বিবেচনা করি। অস্থায়ীদের জীবনটি লুপের পুরো শরীরে বাড়ানো হয় না তবে কেবল লুপ সেটআপের জন্য for এটি কেবলমাত্র পরিসীমা সিনট্যাক্সই নয় যা ক্লাসিক সিনট্যাক্সটিও ক্ষতি করে। আমার মতে, ডিআইপি বিবৃতিতে অস্থায়ীদের জীবনটি লুপের সম্পূর্ণ জীবনের জন্য প্রসারিত হওয়া উচিত।
এডিএ-কিএ মর্ট-ওরা-ওয়াই 15:51

4
@ এডিএ-ক্য্যামোর্ট-ওরা-ওয়াই: আমি একমত হতে চাই যে এখানে একটি সামান্য ভাষার ত্রুটি লুকিয়ে আছে, তবে আমি মনে করি এটি বিশেষত সত্য যে যখনই আপনি সরাসরি কোনও রেফারেন্সের সাথে সরাসরি আবদ্ধ হন তবে আজীবন বর্ধন স্পষ্টভাবে ঘটে। অন্যান্য পরিস্থিতি - এটি অস্থায়ী আজীবন অন্তর্নিহিত সমস্যার অর্ধ-বেকড সমাধানের মতো বলে মনে হয়, যদিও এটির চেয়ে ভাল সমাধান কী হবে তা স্পষ্ট করে বলা যায় না। অস্থায়ী নির্মাণের সময় সম্ভবত একটি স্পষ্ট 'আজীবন এক্সটেনশন' বাক্য গঠন যা এটি বর্তমান ব্লকের শেষ অবধি শেষ করে দেয় - আপনি কী ভাবেন?
ndkrempel

@ এডিএ-কিমোর্ট-ওরা-ই: ... এটি অস্থায়ীটিকে একটি রেফারেন্সের সাথে আবদ্ধ করার মতো একই পরিমাণের পরিমাণ হিসাবে বোঝায়, তবে 'আজীবন এক্সটেনশন' ঘটছে, ইনলাইন (এক অভিব্যক্তিতে) পাঠকের পক্ষে আরও স্পষ্ট হওয়ার সুবিধা রয়েছে পরিবর্তে পৃথক ঘোষণাপত্রের প্রয়োজন হয়) এবং আপনাকে অস্থায়ী নামকরণের প্রয়োজন হয় না।
ndkrempel

উত্তর:


64

এটি কি সঠিক এবং ব্যাপকভাবে প্রশংসিত?

হ্যাঁ, আপনার জিনিসগুলি সম্পর্কে সঠিক ধারণা রয়েছে।

উপরের কোন অংশটি "খারাপ" অংশ, তা এড়ানো উচিত?

খারাপ অংশটি কোনও ফাংশন থেকে ফিরে আসা অস্থায়ীটির জন্য একটি এল-মান রেফারেন্স নিচ্ছে এবং এটি কোনও আর-মান রেফারেন্সে আবদ্ধ করবে। এটি এর মতোই খারাপ:

auto &&t = Vector{1., 2., 3.}.normalize();

অস্থায়ী Vector{1., 2., 3.}জীবনকাল বাড়ানো যায় না কারণ সংকলকটির কোনও ধারণা নেই যে normalizeএটির থেকে ফেরতের মান এটি উল্লেখ করে।

লুপটির জন্য পরিসর-ভিত্তিক সংজ্ঞা পরিবর্তনের মাধ্যমে ভাষার উন্নতি হবে যে লুপের সময়কালের জন্য প্রকাশের জন্য তৈরি টেম্পোরারিগুলি বিদ্যমান?

এটি সি ++ কীভাবে কাজ করে তার সাথে অত্যন্ত বেমানান।

এটি কি অস্থায়ীভাবে বা অভিব্যক্তির জন্য বিভিন্ন অলস-মূল্যায়নের পদ্ধতিতে শৃঙ্খলাবদ্ধ অভিব্যক্তি ব্যবহার করে লোকেদের দ্বারা তৈরি কিছু গ্যাচগুলি প্রতিরোধ করবে? হ্যাঁ. তবে এটির জন্য বিশেষ-কেস সংকলক কোডেরও প্রয়োজন হবে, পাশাপাশি বিভ্রান্ত হবেন যে কেন এটি অন্যান্য অভিব্যক্তি নির্মাণের সাথে কাজ করে না ।

একটি আরও যুক্তিসঙ্গত সমাধান সংকলককে অবহিত করার কিছু উপায় হতে পারে যে কোনও ফাংশনের রিটার্ন মান সর্বদা একটি উল্লেখ thisis যদিও এটি একটি ভাষা-স্তরের সমাধান।

বর্তমানে (যদি সংকলক এটি সমর্থন করে), আপনি এটি তৈরি করতে পারেন যাতে অস্থায়ীভাবে ডাকা যায় normalize না :

struct Vector {
  double x, y, z;
  // ...
  Vector &normalize() & {
     double s = 1./sqrt(x*x+y*y+z*z);
     x *= s; y *= s; z *= s;
     return *this;
  }
  Vector &normalize() && = delete;
};

এটি Vector{1., 2., 3.}.normalize()একটি সংকলন ত্রুটি দেবে, ঠিক আছে যখন v.normalize()কাজ করবে। স্পষ্টতই আপনি এই জাতীয় সঠিক জিনিস করতে সক্ষম হবেন না:

Vector t = Vector{1., 2., 3.}.normalize();

তবে আপনিও ভুল জিনিস করতে পারবেন না।

বিকল্প হিসাবে, মন্তব্যে প্রস্তাবিত হিসাবে, আপনি মূল্যের রেফারেন্স সংস্করণটিকে কোনও রেফারেন্সের পরিবর্তে কোনও মান ফিরিয়ে দিতে পারেন:

struct Vector {
  double x, y, z;
  // ...
  Vector &normalize() & {
     double s = 1./sqrt(x*x+y*y+z*z);
     x *= s; y *= s; z *= s;
     return *this;
  }
  Vector normalize() && {
     Vector ret = *this;
     ret.normalize();
     return ret;
  }
};

যদি Vectorপ্রকৃত সম্পদ সঙ্গে একটি টাইপ সরাতে ছিল, আপনি ব্যবহার করতে পারে Vector ret = std::move(*this);পরিবর্তে। নামযুক্ত রিটার্ন মান অপ্টিমাইজেশন পারফরম্যান্সের ক্ষেত্রে এটি যথাযথভাবে অনুকূল করে তোলে।


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

4
@ndkrempel: হ্যাঁ, কিন্তু আপনি একটি ভাষা বৈশিষ্ট্য উত্থাপন করা এই সমাধানের জন্য (এবং অন্তত 2017 পর্যন্ত অপেক্ষা করতে হবে) চলুন যদি আমি যদি এটা আরো ব্যাপক ছিল পছন্দ করেন, এমন কিছু বিষয় যা অস্থায়ী এক্সটেনশন সমস্যা সমাধান করতে পারে সর্বত্র
নিকল বোলাস

4
+1 শেষ পদ্ধতির পরিবর্তে, deleteআপনি কোনও বিকল্প অপারেশন সরবরাহ করতে পারেন যা কোনও মূল্যকে ফেরত দেয়: Vector normalize() && { normalize(); return std::move(*this); }(আমি বিশ্বাস করি যে normalizeফাংশনের অভ্যন্তরে কলটি লভালু ওভারলোডের কাছে প্রেরণ করবে, তবে এটির কোনওটি পরীক্ষা করা উচিত :)
ডেভিড রডগ্রিজেজ - ড্রিবিস

4
পদ্ধতির এই &/ &&যোগ্যতা আমি কখনই দেখিনি । এটি কি সি ++ 11 এর বা এটি কিছু (সম্ভবত বিস্তৃত) মালিকানাগত সংকলক এক্সটেনশন। ইন্টারেস্টিং সম্ভাবনা দেয়।
খ্রিস্টান রাউ

4
@ ক্রিশ্চিয়ানাআউ: এটি সি ++ ১১-এ নতুন এবং সি -++ 03 "কনস্ট" এবং অ স্থিতিশীল সদস্যের "অস্থির" যোগ্যতার সাথে সাদৃশ্যপূর্ণ, এটি কোনও অর্থে "এটি" যোগ্যতা অর্জন করছে। g ++ 4.7.0 তবে এটি সমর্থন করে না।
ndkrempel

25

(ডাবল এক্স: ভেক্টর {1।, 2., 3। normal। স্বাভাবিককরণ ()) {...}

এটি ভাষার সীমাবদ্ধতা নয়, তবে আপনার কোড নিয়ে সমস্যা। অভিব্যক্তিটি Vector{1., 2., 3.}একটি অস্থায়ী তৈরি করে তবে normalizeফাংশনটি একটি মূল্য-রেফারেন্স দেয় । যেহেতু অভিব্যক্তিটি একটি মূল্যমান , সংকলকটি ধরে নেয় যে বস্তুটি জীবিত থাকবে, তবে এটি একটি অস্থায়ী সম্পর্কিত কারণ হিসাবে সম্পূর্ণ অভিব্যক্তিটি মূল্যায়নের পরে অবজেক্টটি মারা যায়, সুতরাং আপনার ঝুঁকির উল্লেখ রয়েছে।

এখন, আপনি যদি বর্তমান ডিজাইনের পরিবর্তে মান দ্বারা কোনও নতুন অবজেক্ট ফিরিয়ে দিতে আপনার ডিজাইনটি পরিবর্তন করেন তবে কোনও সমস্যা হবে না এবং কোডটি প্রত্যাশা অনুযায়ী কাজ করবে।


4
কোনও constরেফারেন্স কি এই ক্ষেত্রে অবজেক্টের আজীবন প্রসারিত করবে?
ডেভিড স্টোন

4
যা normalize()বিদ্যমান অবজেক্টের পরিবর্তক ফাংশন হিসাবে স্পষ্টভাবে কাঙ্ক্ষিত শব্দার্থকে ভঙ্গ করবে । এইভাবে প্রশ্ন। কোনও অস্থায়ীর পুনরাবৃত্তির নির্দিষ্ট উদ্দেশ্যে ব্যবহৃত হলে একটি "বর্ধিত জীবনকাল" থাকে এবং অন্যথায় নয়, আমি কি মনে করি এটি একটি বিভ্রান্তিকর ভুল ধারণা।
অ্যান্ডি রস

4
@ অ্যান্ড্যরোস: কেন? কোনও আর-মান রেফারেন্সে আবদ্ধ কোনও অস্থায়ী (বা const&) এর আজীবন প্রসারিত।
নিকল বোলাস

4
@ndkrempel: কিন্তু, এর এসবের মাঝেই সীমাবদ্ধ না পরিসর ভিত্তিক লুপ জন্য, একই সমস্যা যদি আপনি একটি রেফারেন্স প্রদানকারীর সাথে যুক্ত হন আসতে হবে: Vector & r = Vector{1.,2.,3.}.normalize();। আপনার ডিজাইনের সেই সীমাবদ্ধতা রয়েছে এবং এর অর্থ এই যে আপনি হয় মূল্য দিয়ে ফিরতে ইচ্ছুক (যা অনেক পরিস্থিতিতে অনুভূত হতে পারে, এবং আরও অনেক কিছু মূল্য-রেফারেন্স এবং পদক্ষেপ সহ ) অথবা অন্যথায় আপনার সমস্যাটির জায়গায় সমস্যাটি পরিচালনা করতে হবে কল: একটি সঠিক পরিবর্তনশীল তৈরি করুন, তারপরে এটি লুপে ব্যবহার করুন use এছাড়াও লক্ষ করুন যে অভিব্যক্তি দুটি বস্তু Vector v = Vector{1., 2., 3.}.normalize().negate();তৈরি করে ...
ডেভিড রদ্রিগেজ - ড্রিবাস

4
@ ডেভিডরোড্রিগিজ-ড্রিবিয়াস: কনস্ট্যান্ড-রেফারেন্সের সাথে জড়িত থাকার সমস্যাটি হ'ল: T const& f(T const&);সম্পূর্ণরূপে ঠিক। T const& t = f(T());পুরোপুরি ঠিক আছে। এবং তারপরে, অন্য টিইউতে আপনি এটি আবিষ্কার করেন T const& f(T const& t) { return t; }এবং আপনি কেঁদেছেন ... যদি operator+মানগুলিতে চালিত হয় তবে এটি নিরাপদ ; তারপরে সংকলকটি অনুলিপিটিকে অনিচ্ছায়িত করতে পারে (গতি চান? মান দ্বারা পাস করুন) তবে এটি একটি বোনাস। অস্থায়ীগুলির কেবলমাত্র বাঁধাইকে আমি অনুমতি দিই তা হ'ল r- মান রেফারেন্সের জন্য বাধ্যতামূলক, তবে ফাংশনগুলি তারপরে সুরক্ষার জন্য মানগুলি ফেরত পাঠানো উচিত এবং অনুলিপি / মুভ শব্দার্থক অনুলিপিতে নির্ভর করা উচিত।
ম্যাথিউ এম।

4

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

Vector v{1., 2., 3.};
auto foo = somefunction1(v, 17);
auto bar = somefunction2(true, v, 2, foo);
auto baz = somefunction3(bar.quun(v), 93.2, v.qwarv(foo));

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

auto normalized(Vector v) -> Vector {return v.normalize();}
auto negated(Vector v) -> Vector {return v.negate();}

এবং তারপরে লুপগুলি লিখুন

for( double x : negated(normalized(v)) ) { ... }

এবং

for( double x : normalized(Vector{1., 2., 3}) ) { ... }

এটি আইএমও আরও ভাল পাঠযোগ্য এবং এটি আরও নিরাপদ। অবশ্যই এটির জন্য একটি অতিরিক্ত অনুলিপি প্রয়োজন, তবে হিপ-বরাদ্দ হওয়া ডেটার জন্য এটি সম্ভবত সস্তা সি ++ 11 সরানো অপারেশনে করা যেতে পারে।


ধন্যবাদ যথারীতি, অনেক পছন্দ আছে। আপনার পরামর্শটি কার্যকর হতে পারে না এমন একটি পরিস্থিতি হ'ল উদাহরণস্বরূপ, যদি ভেক্টরটি 1000 ডাবলসের অ্যারে (গাদা বরাদ্দ নয়) হয়। দক্ষতার বাণিজ্য, ব্যবহারের সহজতা এবং ব্যবহারের সুরক্ষা trade
ndkrempel

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