কোনও কনস্ট্যান্ড রেফারেন্স ক্লাসের সদস্য কি অস্থায়ী জীবন দীর্ঘায়িত করে?


171

কেন এটি করে:

#include <string>
#include <iostream>
using namespace std;

class Sandbox
{
public:
    Sandbox(const string& n) : member(n) {}
    const string& member;
};

int main()
{
    Sandbox sandbox(string("four"));
    cout << "The answer is: " << sandbox.member << endl;
    return 0;
}

এর আউটপুট দিন:

উত্তরটা হচ্ছে:

পরিবর্তে:

উত্তর: চার


39
এবং কেবল আরও মজাদার জন্য, আপনি যদি লিখেছিলেন cout << "The answer is: " << Sandbox(string("four")).member << endl;তবে এটির কাজের নিশ্চয়তা দেওয়া হবে।

7
@ রোজারপেট আপনি কেন ব্যাখ্যা করতে পারেন?
পাওলো এম

16
যে কারও কৌতূহল আছে তার উদাহরণস্বরূপ, রজার প্যাট পোস্ট করেছেন কারণ স্ট্রিং ("চার") অস্থায়ী এবং সম্পূর্ণ অযৌক্তিকর শেষে সেই অস্থায়ী বিনষ্ট হয় , সুতরাং যখন SandBox::memberতার পাঠ করা হয় তখন অস্থায়ী স্ট্রিংটি এখনও বেঁচে থাকে
পিসিএএফ

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

@ পিসিএএফ: আপনি দয়া করে ব্যাখ্যা করতে পারেন কেন string("four")পুরো প্রকাশের শেষে অস্থায়ীটি ধ্বংস হয়, এবং Sandboxনির্মাণকারীর বাইরে যাওয়ার পরে নয় ? পোটোসওয়টারের উত্তরটি বলে যে কনস্ট্রাক্টরের কর্টর-ইনিশিয়ালাইজারের একটি রেফারেন্স সদস্যকে অস্থায়ীভাবে আবদ্ধ করা (§১২. [.২ [শ্রেণি.বেস.ইনাইট]) কনস্ট্রাক্টরটি প্রস্থান না হওয়া অবধি স্থায়ী থাকে।
টেলর নিকোলস

উত্তর:


166

শুধুমাত্র স্থানীয় const রেফারেন্সগুলি আজীবন দীর্ঘায়িত করে।

স্ট্যান্ডার্ড রেফারেন্স ঘোষণার প্রারম্ভিকদের উপরের বিভাগ -8.5.3 / 5, [dcl.init.ref] এ এই জাতীয় আচরণ নির্দিষ্ট করে। আপনার উদাহরণের রেফারেন্সটি কনস্ট্রাক্টরের যুক্তিতে আবদ্ধ n, এবং যখন অবজেক্টটি nসুযোগের বাইরে চলে যাবে তখন অবৈধ হয়ে যায়।

আজীবন এক্সটেনশন কোনও ফাংশন আর্গুমেন্টের মাধ্যমে অস্থায়ী হয় না। §12.2 / 5 [শ্রেণী.কালীন]:

দ্বিতীয় প্রসঙ্গটি হ'ল যখন কোনও রেফারেন্স অস্থায়ীভাবে আবদ্ধ হয়। নীচে নির্দিষ্ট করা ব্যতীত যে অস্থায়ী রেফারেন্সটি সীমাবদ্ধ বা অস্থায়ী যা একটি সাবওজেক্টের সম্পূর্ণ অবজেক্ট যা অস্থায়ীভাবে আবদ্ধ হয় নিচে বর্ণিত ব্যতীত রেফারেন্সের আজীবন স্থায়ী থাকে। কনস্ট্রাক্টরের কর্টোর-ইনিশিয়ালাইজারে রেফারেন্স সদস্যের সাথে অস্থায়ীভাবে আবদ্ধ (.6১২..2.২ [শ্রেণি.বেস.ইনাইট]) কনস্ট্রাক্টরটি প্রস্থান না হওয়া অবধি স্থায়ী থাকে। একটি ফাংশন কলের একটি রেফারেন্স প্যারামিটারে আবদ্ধ একটি অস্থায়ী (§5.2.2 [expr.call]) কলযুক্ত পূর্ণ এক্সপ্রেশন শেষ না হওয়া পর্যন্ত স্থির থাকে।


49
আরও মানব-বান্ধব ব্যাখ্যার জন্য আপনার গট ডাব্লু # 88 টিও দেখতে হবে: herbsutter.com/2008/01/01/…
নাথান আর্নস্ট

1
আমি মনে করি এটি যদি আরও পরিষ্কার হয় যে মানটি "দ্বিতীয় প্রসঙ্গটি হল যখন কোনও রেফারেন্স একটি মূল্যের সাথে আবদ্ধ থাকে"। ওপির কোডে আপনি বলতে পারেন যে memberএটি একটি অস্থায়ী memberসাথে nআবদ্ধ , কারণ memberএকই বস্তুর nসাথে আবদ্ধ হওয়ার মাধ্যম দিয়ে আরম্ভ করা বাধ্য, এবং এটি আসলে এই ক্ষেত্রে একটি অস্থায়ী বস্তু।
এমএম

2
@ মিমি এমন কেস রয়েছে যেখানে মূল্যবৃদ্ধি সম্পন্ন ল্যাভালু বা এক্সভালিউ ইনিশিয়ালাইজারগুলি মূল্যকে প্রসারিত করবে। আমার প্রস্তাবের কাগজ P0066 বিষয়ক অবস্থা পর্যালোচনা করে।
পোটোসওয়টার

1
সি ++ 11 অনুসারে, মূল্যের উল্লেখগুলি কোনও constকোয়েফায়ারের প্রয়োজন ছাড়াই অস্থায়ী জীবনকে দীর্ঘায়িত করে ।
GetFree

3
@ কীভিনফ্যাভো হ্যাঁ, কোনও মৃত অবজেক্ট ব্যবহার করা সর্বদা ইউবি হয়
পোটোটোসওয়টার

30

কী ঘটেছে তা বোঝানোর সহজ উপায় এখানে:

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

আপনি যদি চান এমন আচরণটি প্রদর্শন করতে আপনার প্রোগ্রামটি ঠিক করতে চান তবে নিম্নলিখিত পরিবর্তনগুলি করুন:

int main()
{
    string temp = string("four");    
    Sandbox sandbox(temp);
    cout << sandbox.member << endl;
    return 0;
}

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

আমি যা প্রস্তাব দিচ্ছি তা হল স্যান্ডবক্স.মেমারকে একটি হিসাবে সংজ্ঞায়িত করা const string member;এটি অস্থায়ী প্যারামিটারের ডেটা মেম্বার ভেরিয়েবলকে অস্থায়ী প্যারামিটার হিসাবে অর্পণ করার পরিবর্তে সদস্য ভেরিয়েবেলে অনুলিপি করে।


যদি আমি এটি করি: const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;এটি কি এখনও কাজ করবে?
ইয়ভেস

@ থমাস const string &temp = string("four");একই ফল দেয় যেমন const string temp("four"); আপনি decltype(temp)নির্দিষ্টভাবে ব্যবহার না করেন
এমএম

@ এমএম অনেক ধন্যবাদ এখন আমি পুরোপুরি এই প্রশ্নটি বুঝতে পারি।
ইয়ভেস

However, this is bad practice.- কেন? টেম্প এবং এতে থাকা উভয় বস্তু যদি একই স্কোপটিতে স্বয়ংক্রিয় স্টোরেজ ব্যবহার করে তবে এটি কি 100% নিরাপদ নয়? এবং যদি আপনি এটি না করেন, আপনি যদি স্ট্রিংটি খুব বড় এবং অনুলিপি করে অনুলিপি করেন তবে আপনি কী করবেন?
সর্বাধিক

2
@ ম্যাক্স, কারণ শ্রেণিটি সঠিক সুযোগ পাওয়ার জন্য অস্থায়ীভাবে পাসগুলি প্রয়োগ করে না। এর অর্থ হ'ল একদিন আপনি এই প্রয়োজনীয়তাটি ভুলে যেতে পারেন, অবৈধ অস্থায়ী মান পাস করুন এবং সংকলক আপনাকে সতর্ক করবে না।
অ্যালেক্স চে

5

প্রযুক্তিগতভাবে বলতে গেলে, এই প্রোগ্রামটি আসলে স্ট্যান্ডার্ড আউটপুটে (যা শুরু করার জন্য একটি বাফার স্ট্রিম) কোনও কিছু আউটপুট দেওয়ার প্রয়োজন হয় না।

  • cout << "The answer is: "বিট নির্গত হবে "The answer is: "মধ্যে বাফার stdout- এ করুন।

  • তারপরে << sandbox.memberবিটটি ঝুঁকির রেফারেন্স সরবরাহ করবে operator << (ostream &, const std::string &), যা অনির্ধারিত আচরণের জন্য প্রার্থনা করে

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


2
যখন ইউবি থাকে, পুরো প্রোগ্রামটির আচরণটি সংজ্ঞায়িত হয় - এটি কার্যকর করার কোনও নির্দিষ্ট সময়ে শুরু হয় না। সুতরাং আমরা নিশ্চিতভাবে বলতে পারি না যে "The answer is: "কোথাও লেখা হবে।
টবি স্পিড 14

0

কারণ আপনার অস্থায়ী স্ট্রিংটি স্যান্ডবক্স কনস্ট্রাক্টর ফিরে যাওয়ার পরে সুযোগের বাইরে চলে গিয়েছিল এবং এটি দখল করা স্ট্যাকটি অন্য কয়েকটি কারণে পুনরায় দাবী করা হয়েছিল।

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


7
"কখনই নয়" একটি ভীষণ শক্ত শব্দ।
ফ্রেড লারসন 21

17
ক্লাস মেম্বারদের কখনই আপনার কোনও জিনিসের রেফারেন্স রাখতে হবে না। এমন কিছু ক্ষেত্রে রয়েছে যেখানে আপনাকে অন্যান্য সামগ্রীর জন্য রেফারেন্স রাখতে হবে, এবং অনুলিপিগুলি নয়, এই ক্ষেত্রে রেফারেন্সগুলি পয়েন্টারগুলির চেয়ে পরিষ্কার সমাধান হয়।
ডেভিড রদ্রিগেজ - ড্রিবিস

0

আপনি এমন কিছু উল্লেখ করছেন যা হারিয়ে গেছে which নিম্নলিখিত কাজ করবে

#include <string>
#include <iostream>

class Sandbox
{

public:
    const string member = " "; //default to whatever is the requirement
    Sandbox(const string& n) : member(n) {}//a copy is made

};

int main()
{
    Sandbox sandbox(string("four"));
    std::cout << "The answer is: " << sandbox.member << std::endl;
    return 0;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.