পদ্ধতি চেইনে সি ++ এক্সিকিউশন অর্ডার


108

এই প্রোগ্রামটির ফলাফল:

#include <iostream> 
class c1
{   
  public:
    c1& meth1(int* ar) {
      std::cout << "method 1" << std::endl;
      *ar = 1;
      return *this;
    }
    void meth2(int ar)
    {
      std::cout << "method 2:"<< ar << std::endl;
    }
};

int main()
{
  c1 c;
  int nu = 0;
  c.meth1(&nu).meth2(nu);
}

হল:

method 1
method 2:0

কেন শুরু হয় nuনা যখন 1 meth2()?


41
@ মার্টিনবোনার: যদিও আমি উত্তরটি জানি, তবে আমি এটিকে শব্দের কোনও অর্থে "সুস্পষ্ট" বলব না এবং এমনকি যদি তাও হয় তবে এটি ডাউন ড্রাইভ দ্বারা চালিত হওয়ার কোনও শালীন কারণ হবে না। হতাশাজনক!
অরবিটে মেঘলা হালকা ঘোড়দৌড়ের দৌড়

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


@ জানহুদেক এটি হ'ল ফাংশনাল প্রোগ্রামিং ফাংশন বিশুদ্ধতার উপর এত বেশি জোর দেয়।
ফারাপ

2
উদাহরণস্বরূপ, একটি স্ট্যাক ভিত্তিক কলিং সম্মেলন সম্ভবত ধাক্কা পছন্দ করেন nu, &nuএবং cস্ট্যাকে যাতে উপর, তারপর ডাকা meth1, স্ট্যাক উপর ফলাফলের ধাক্কা, তারপর ডাকা meth2, যখন একটি রেজিস্টার ভিত্তিক কলিং সম্মেলন করতে চান লোড করুন cএবং &nuরেজিস্টারগুলিতে, আবেদন করুন meth1, nuএকটি রেজিস্টারে লোড করুন , তারপরে প্রার্থনা করুন meth2
নিল

উত্তর:


66

কারণ মূল্যায়নের আদেশটি অনির্ধারিত।

আপনি দেখতে পাচ্ছেন nuমধ্যে mainথেকে মূল্যায়ন করা হচ্ছে 0আগেই meth1বলা হয়। এই শৃঙ্খলাবদ্ধতা সঙ্গে সমস্যা। আমি এটি না করার পরামর্শ দিই।

কেবল একটি সুন্দর, সাধারণ, পরিষ্কার, সহজেই পঠনযোগ্য, সহজেই বোঝার প্রোগ্রাম করুন:

int main()
{
  c1 c;
  int nu = 0;
  c.meth1(&nu);
  c.meth2(nu);
}

14
একটি সম্ভাবনা রয়েছে, কিছু ক্ষেত্রে মূল্যায়ন আদেশ পরিষ্কার করার প্রস্তাব , যা এই সমস্যাটিকে সংশোধন করে, সি ++ 17
রিভলবার_অসেলোট

7
আমি পদ্ধতি শৃঙ্খলা পছন্দ করি (উদাহরণস্বরূপ <<আউটপুট জন্য, এবং নির্মাণকারীদের সাথে অনেক যুক্তিযুক্ত জটিল বস্তুর জন্য "অবজেক্ট বিল্ডার" - তবে এটি আউটপুট আর্গুমেন্টের সাথে সত্যিই খারাপভাবে মিশে যায়
মার্টিন বোনার মনিকা

34
আমি কি এই অধিকার বুঝতে পারি? মূল্যায়ন ক্রম meth1এবং meth2সংজ্ঞায়িত করা হয়, তবে প্যারামিটারের মূল্যায়ন এর meth2আগে meth1বলা হতে পারে ...?
রডি

7
যতক্ষণ পদ্ধতিগুলি বোধগম্য হয় কেবল ততক্ষণ পদ্ধতি চেইন করা ঠিক থাকে এবং কেবলমাত্র ইনভোট্যান্টকে সংশোধন করে (যার জন্য প্রভাবগুলি ভালভাবে আদেশ করা হয়, কারণ দ্বিতীয় ফলাফলটি প্রথমের ফলাফলের জন্য ডাকা হয়)।
জানু হুডেক

4
এটি যৌক্তিক, যখন আপনি এটি সম্পর্কে ভাবেন। এটি কাজ করেmeth2(meth1(c, &nu), nu)
বারটেকচম

29

আমি মনে করি মূল্যায়নের আদেশ সংক্রান্ত খসড়া মানের এই অংশটি প্রাসঙ্গিক:

1.9 প্রোগ্রাম কার্যকর

...

  1. উল্লিখিত ব্যতীত, পৃথক অপারেটরগুলির ক্রিয়াকলাপগুলির মূল্যায়ন এবং স্বতন্ত্র এক্সপ্রেশনগুলির subexpresstions অসমর্থিত। অপারেটরের অপারেন্ডসের মান গণনা অপারেটরের ফলাফলের মান গণনার আগে ক্রমযুক্ত হয়। যদি কোনও স্কেলার অবজেক্টের পার্শ্ব প্রতিক্রিয়া একই স্কেলার অবজেক্টের অন্য কোনও পার্শ্ব প্রতিক্রিয়া বা একই স্কেলার অবজেক্টের মান ব্যবহার করে একটি মান গণনার তুলনায় অসম্পূর্ণ হয় এবং তারা সম্ভাব্য একযোগে না হয় তবে আচরণটি অপরিবর্তিত

এবং যদিও:

5.2.2 ফাংশন কল

...

  1. [দ্রষ্টব্য: পোস্টফিক্স এক্সপ্রেশন এবং আর্গুমেন্টগুলির মূল্যায়নগুলি একে অপরের তুলনায় অনিচ্ছাকৃত। ফাংশনটি প্রবেশের আগে যুক্তির মূল্যায়নের সমস্ত পার্শ্ব প্রতিক্রিয়াগুলি ক্রমযুক্ত হয় - শেষ নোট]

সুতরাং আপনার লাইনের c.meth1(&nu).meth2(nu);জন্য, চূড়ান্ত কলের জন্য ফাংশন কল অপারেটরের ক্ষেত্রে অপারেটরে কী ঘটছে তা বিবেচনা করুন meth2, সুতরাং আমরা স্পষ্টভাবে পোস্টফিক্স এক্সপ্রেশন এবং যুক্তির মধ্যে ভাঙ্গন দেখতে পাচ্ছি nu:

operator()(c.meth1(&nu).meth2, nu);

পোস্টসাফিক্স মত প্রকাশ ও যুক্তির মূল্যায়ন চূড়ান্ত ফাংশন কল জন্য (পোস্টসাফিক্স অভিব্যক্তি অর্থাৎ c.meth1(&nu).meth2এবং nu) হয় একে অপরের সাথে unsequenced আপেক্ষিক অনুযায়ী ফাংশন কল উপরে নিয়ম। সুতরাং, স্কেলার অবজেক্টে পোস্টফিক্স এক্সপ্রেশনটির গণনার পার্শ্ব-প্রতিক্রিয়াটি ফাংশন কলের আগে arযুক্তির মূল্যায়নের তুলনায় অনিচ্ছাকৃত । দ্বারা প্রোগ্রাম সঞ্চালনের উপরে নিয়ম, এই অনির্ধারিত আচরণ।numeth2

অন্য কথায়, কলের পরে কলটিতে nuযুক্তির মূল্যায়ন করার জন্য সংকলকটির কোনও প্রয়োজন নেই - মূল্যায়নকে প্রভাবিত করার কোনও পার্শ্ব-প্রতিক্রিয়া ধরে নেওয়া নিখরচায় ।meth2meth1meth1nu

উপরের দ্বারা উত্পাদিত সমাবেশ কোডটি mainফাংশনে নিম্নলিখিত ক্রমটি অন্তর্ভুক্ত করে :

  1. পরিবর্তনশীল nuস্ট্যাক বরাদ্দ এবং 0 দিয়ে আরম্ভ করা হয়।
  2. একটি রেজিস্টার ( ebxআমার ক্ষেত্রে) এর মানটির একটি অনুলিপি পানnu
  3. ঠিকানা nuএবং cপ্যারামিটার রেজিস্টার মধ্যে লোড করা হয়
  4. meth1 বলা হয়
  5. ফেরত মান রেজিস্টার এবং পূর্বে ক্যাশে মান এর nuমধ্যে ebxরেজিস্টার প্যারামিটার রেজিস্টার মধ্যে লোড করা হয়
  6. meth2 বলা হয়

সমালোচনামূলকভাবে, 5 ধাপে সংকলক উপরে nuপদক্ষেপ 2 থেকে ক্যাশেড মানটি ফাংশন কলটিতে পুনরায় ব্যবহার করতে দেয় meth2। এখানে এটি সম্ভাবনাটিকে অগ্রাহ্য করে - nuকলটিতে meth1- 'কার্যত নির্ধারিত আচরণ' - এ কল করা হতে পারে ।

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


2
এটা ভুল. কলিং ফাংশনগুলিতে ফাংশন কলগুলি অনির্দিষ্টভাবে ক্রমান্বয়ে ডাব্লু / আর / টি অন্যান্য মূল্যায়ন হয় (যদি না সিক্যুয়েন্সড-সীমাবদ্ধতার আগে বাধা আরোপ করা হয়); তারা আন্তঃপ্রণোদিত হয় না।
টিসি

1
@ টিটিসি - ফাংশন কলগুলি ইন্টারলিভড হওয়ার বিষয়ে আমি কখনও কিছু বলিনি। আমি কেবল অপারেটরগুলির পার্শ্ব প্রতিক্রিয়াগুলিকেই উল্লেখ করেছি। যদি আপনি উপরের দ্বারা উত্পাদিত অ্যাসেম্বলি কোডটি লক্ষ্য করেন তবে আপনি দেখতে পাবেন যে meth1এটি আগে কার্যকর করা হয়েছিল meth2, তবে এর জন্য প্যারামিটারটি কল করার আগে একটি রেজিস্টারে ক্যাশেডের meth2মান - অর্থাৎ সংকলকটি সম্ভাব্য পার্শ্ব-প্রতিক্রিয়াগুলিকে অগ্রাহ্য করেছে, যা আমার উত্তর সাথে সামঞ্জস্যপূর্ণ। numeth1
স্মিহি

1
আপনি ঠিক দাবি করছেন যে - "এর পার্শ্ব-প্রতিক্রিয়া (অর্থাত্ আর এর মান নির্ধারণ করা) কল করার আগে ক্রমানুসারে গ্যারান্টিযুক্ত নয়"। কোনও ফাংশন কলে (যা হয় c.meth1(&nu).meth2) পোস্টফিক্স-এক্সপ্রেশনের মূল্যায়ন এবং সেই কলটির আর্গুমেন্টের মূল্যায়ন ( nu) সাধারণত অনিচ্ছাকৃত তবে 1) এর পার্শ্ব প্রতিক্রিয়াগুলি সমস্ত প্রবেশের আগে meth2এবং 2) ক্রমযুক্ত যেহেতু c.meth1(&nu)একটি ফাংশন কল , এটি অনির্দিষ্টকালের জন্য মূল্যায়নের সাথে ক্রমযুক্ত nu। ইনসাইড meth2, যদি একরকম মধ্যে পরিবর্তনশীল একটি পয়েন্টার প্রাপ্ত main, এটা সবসময় 1. দেখতে হবে
টিসি

2
"তবে অপারেটরগুলির গণনার পার্শ্ব-প্রতিক্রিয়া (যেমন আর এর মান নির্ধারণ) উপরের কিছু (2 হিসাবে) এর আগে সিকোয়েন্সড হওয়ার নিশ্চয়তা নেই।" meth2আপনি উদ্ধৃত করছেন এমন সিপ্রেফারেন্স পৃষ্ঠার আইটেম 3-এ উল্লিখিত কল করার আগেই এটি সম্পূর্ণরূপে নিশ্চিত হওয়ার গ্যারান্টিযুক্ত (যা আপনি যথাযথভাবে উদ্ধৃত করতেও অবহেলা করেছেন)।
টিসি

1
আপনি কিছু ভুল করেছেন, এবং এটি আরও খারাপ করেছেন। এখানে একেবারে কোনও অপরিবর্তিত আচরণ নেই। উদাহরণটি রেখে অতীত [intro.execution] / 15 পড়তে থাকুন।
টিসি

9

1998 সি ++ স্ট্যান্ডার্ডে বিভাগ 5, প্যারা 4

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

(আমি পাদটীকা # 53 এর একটি রেফারেন্স বাদ দিয়েছি যা এই প্রশ্নের সাথে প্রাসঙ্গিক নয়)।

মূলত, &nuকল করার আগে অবশ্যই মূল্যায়ন করা উচিত c1::meth1()এবং ফোন করার আগে nuঅবশ্যই মূল্যায়ন করতে হবে c1::meth2()। তবে এর nuআগে মূল্যায়ন করার মতো কোনও প্রয়োজনীয়তা নেই &nu(যেমন nu, প্রথমে মূল্যায়ন করার অনুমতি দেওয়া হয় , তারপরে &nuএবং তারপরে c1::meth1()বলা হয় - যা আপনার সংকলকটি যা করছে তা হতে পারে)। অভিব্যক্তি *ar = 1মধ্যে c1::meth1()তাই নিশ্চিত নয় আগে মূল্যায়ন করা nuমধ্যে main()মূল্যায়ন করা হয়, যাতে এ পাস করার c1::meth2()

পরবর্তীতে সি ++ স্ট্যান্ডার্ড (যা আমি বর্তমানে পিসিতে ব্যবহার করব না আমি আজ রাতে ব্যবহার করছি) মূলত একই ধারা রয়েছে।


7

আমি মনে করি সংকলন করার সময়, ফান্ট মেথ 1 এবং মেথ 2 প্রকৃতপক্ষে ডাকার আগে, তাদের কাছে প্যারামিটারগুলি পাস করা হয়েছিল। আমি যখন আপনি "c.meth1 (& nu) .meth2 (nu) ব্যবহার করেন তখন আমার অর্থ; মান nu = 0 কে meth2 এ চলে গেছে, সুতরাং "nu" এর পরে পরিবর্তিত হওয়া কোনও বিষয় নয়।

আপনি এটি চেষ্টা করতে পারেন:

#include <iostream> 
class c1
{
public:
    c1& meth1(int* ar) {
        std::cout << "method 1" << std::endl;
        *ar = 1;
        return *this;
    }
    void meth2(int* ar)
    {
        std::cout << "method 2:" << *ar << std::endl;
    }
};

int main()
{
    c1 c;
    int nu = 0;
    c.meth1(&nu).meth2(&nu);
    getchar();
}

এটি আপনি চান উত্তর পেতে হবে

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