কনস্ট্যান্ড স্ট্যান্ড :: স্ট্রিং পাস করার দিনগুলি কি প্যারামিটার হিসাবে শেষ হবে?


604

আমি ঔষধি Sutter দ্বারা একটি সাম্প্রতিক আলাপ যারা যে কারণে পাস শুনেছি std::vectorএবং std::stringদ্বারা const &মূলত চলে গেছে। তিনি পরামর্শ দিয়েছিলেন যে নীচের মতো একটি ফাংশন রচনা এখন পছন্দনীয়:

std::string do_something ( std::string inval )
{
   std::string return_val;
   // ... do stuff ...
   return return_val;
}

আমি বুঝতে পেরেছি যে return_valফাংশনটি ফিরে আসার সময়টির একটি মূল্যায়ন হবে এবং তাই সস্তার শব্দার্থকগুলি ব্যবহার করে ফিরে দেওয়া যেতে পারে, যা খুব সস্তা। তবে, invalএখনও একটি রেফারেন্সের আকারের তুলনায় অনেক বড় (যা সাধারণত পয়েন্টার হিসাবে প্রয়োগ করা হয়)। এটি কারণ হ'ল std::stringএকটি পয়েন্টার সহ char[]সংক্ষিপ্ত স্ট্রিং অপ্টিমাইজেশনের জন্য সদস্য সহ বিভিন্ন উপাদান রয়েছে । সুতরাং এটি আমার কাছে মনে হয় যে রেফারেন্স দিয়ে পাস করা এখনও একটি ভাল ধারণা।

কেউ কি ব্যাখ্যা করতে পারেন যে হার্ব কেন এটি বলেছেন?


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

আকর্ষণীয়, সুতরাং যদি আপনি যাইহোক যাইহোক একটি অনুলিপি তৈরি করতে যাচ্ছেন তবে পাস-বাই-মানটি পাস-বাই-রেফারেন্সের চেয়ে দ্রুততর হবে।
বেনজ

3
@Sz। আমি নকল হিসাবে নকল এবং শ্রেণীবদ্ধ হিসাবে প্রশ্ন সংবেদনশীল। আমি এই মামলার বিবরণ মনে রাখি না এবং সেগুলি পুনরায় পর্যালোচনা করি না। পরিবর্তে আমি কেবল ভুল করেছিলাম এই ধারণাটি নিয়ে আমার মন্তব্য মুছতে চলেছি। এটি আমার নজরে আনার জন্য আপনাকে ধন্যবাদ।
হাওয়ার্ড হিন্যান্ট

2
@ হাওয়ার্ডহিন্যান্ট, আপনাকে অনেক ধন্যবাদ, যখন এই মনোযোগ এবং সংবেদনশীলতার এই স্তরটি যখন আসে তখন এটি সর্বদা একটি মূল্যবান মুহুর্ত হয়, এটি এত সতেজ হয়! (আমি অবশ্যই আমার মুছে ফেলব, অবশ্যই।)
জেড।

উত্তর:


393

হার্ব তার যা বলার কারণ তা এই জাতীয় মামলার কারণ।

ধরা যাক আমি ফাংশন Aযা কল ফাংশন B, যা ফাংশন কল C। এবং Aএকটি স্ট্রিং মাধ্যমে Bএবং মধ্যে পাস CAজানে না বা যত্ন করে না C; সব Aসম্পর্কে জানেন B। যে, Cএর একটি বাস্তবায়ন বিশদ B

ধরা যাক যে এটিকে সংজ্ঞায়িত করা হয়েছে:

void A()
{
  B("value");
}

যদি বি এবং সি স্ট্রিংটি নেয় const&, তবে এটির মতো কিছু দেখাচ্ছে:

void B(const std::string &str)
{
  C(str);
}

void C(const std::string &str)
{
  //Do something with `str`. Does not store it.
}

সব ঠিক আছে। আপনি সবেমাত্র পয়েন্টারগুলি পার করছেন, কোনও অনুলিপি নেই, চলমান নেই, সবাই খুশি। Cএটি গ্রহণ করে const&কারণ এটি স্ট্রিং সংরক্ষণ করে না। এটি কেবল এটি ব্যবহার করে।

এখন, আমি একটি সাধারণ পরিবর্তন করতে চাই: Cকোথাও স্ট্রিংটি সঞ্চয় করা দরকার।

void C(const std::string &str)
{
  //Do something with `str`.
  m_str = str;
}

হ্যালো, অনুলিপি নির্মাণকারী এবং সম্ভাব্য মেমরি বরাদ্দ ( শর্ট স্ট্রিং অপটিমাইজেশন (এসএসও) উপেক্ষা করুন )। সি ++ 11 এর সরানো শব্দার্থবিজ্ঞানের অযথা অনুলিপি-অনুলিপিটি অপসারণ করা সম্ভব হবে, তাই না? এবং Aএকটি অস্থায়ী পাস; ডেটা অনুলিপিC করার কোনও কারণ নেই । এটি যা দিয়েছিল তা কেবল পলাতক হওয়া উচিত।

এটা না পারলে। কারণ এটি লাগে const&

যদি আমি Cএর পরামিতিটিকে মান অনুসারে নিতে পরিবর্তন Bকরি তবে এটি সেই প্যারামিটারে অনুলিপি তৈরি করে; আমি কিছুই লাভ।

সুতরাং আমি যদি strসমস্ত ফাংশনটির মধ্যে দিয়ে কেবল মূল্যটি দিয়ে চলেছি, std::moveচারপাশের ডেটাগুলিকে বদলে ফেলার উপর নির্ভর করে , আমাদের এই সমস্যাটি হবে না। কেউ যদি এটি ধরে রাখতে চায় তবে তারা পারে। যদি তারা না করে তবে ওহ ভাল।

এটা কি আরও ব্যয়বহুল? হ্যাঁ; রেফারেন্স ব্যবহারের চেয়ে কোনও মান হিসাবে স্থানান্তর করা আরও ব্যয়বহুল। এটি অনুলিপি তুলনায় কম ব্যয়বহুল? এসএসও সহ ছোট স্ট্রিংয়ের জন্য নয়। এটা কি মূল্য?

এটি আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে। আপনি মেমরি বরাদ্দকে কতটা ঘৃণা করেন?


2
আপনি যখন বলছেন যে রেফারেন্সগুলি ব্যবহারের চেয়ে কোনও মানে স্থানান্তর করা আরও ব্যয়বহুল, তখনও এটি ধ্রুবক পরিমাণে (স্ট্রিংয়ের দৈর্ঘ্যের চেয়ে আলাদা হয়ে সরানো) ডান?
নিল জি

3
@ নীলজি: "বাস্তবায়ন নির্ভর" এর অর্থ কী আপনি বুঝতে পেরেছেন? আপনি যা বলছেন তা ভুল, কারণ এসএসও বাস্তবায়িত হয় কিনা তা নির্ভর করে ।
iljarn

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

8
@ নীলজি: অবশ্যই, তবে আপনার মূল প্রশ্নটি ছিল " এটি একটি ধ্রুবক পরিমাণের চেয়ে এখনও বেশি ব্যয়বহুল (স্ট্রিংয়ের দৈর্ঘ্যের তুলনায় স্বতঃপ্রণোদিত ) সঠিক ছিল? " আমি যে বিষয়টি তৈরির চেষ্টা করছি তা হ'ল, এটি বিভিন্নভাবে আরও ব্যয়বহুল হতে পারে স্ট্রিংয়ের দৈর্ঘ্যের উপর নির্ভর করে ধ্রুব পরিমাণগুলি, যা "না" হিসাবে সংক্ষিপ্ত হয়ে যায়।
iljarn

13
স্ট্রিংটি কেন movedমান ক্ষেত্রে বি থেকে সি হবে? বি যদি হয় B(std::string b)এবং সি হয় C(std::string c)হয় হয় আমাদের C(std::move(b))বিতে ফোন করতে হবে বা bপ্রস্থান না হওয়া অবধি অপরিবর্তিত থাকতে হবে (এভাবে 'অপ্রচলিত') B। (সম্ভবত নিখুঁত কম্পাইলার অধীনে স্ট্রিং সরানো হবে যেমন-যদি নিয়ম যদি bকল পর ব্যবহার করা হয় না কিন্তু আমি মনে করি না একটি শক্তিশালী গ্যারান্টি নেই না।) একই কপি জন্য সত্য strথেকে m_str। এমনকি যদি কোনও ফাংশন প্যারামটারটি কোনও মূল্য দিয়ে শুরু করা হয় তবে এটি ফাংশনের অভ্যন্তরে একটি লভ্যালু এবং std::moveসেই ল্যাভেলু থেকে সরানো প্রয়োজন।
পিক্সেলচেমিস্ট

163

কনস্ট্যান্ড স্ট্যান্ড :: স্ট্রিং পাস করার দিনগুলি কি প্যারামিটার হিসাবে শেষ হবে?

কোন । অনেক লোক এই পরামর্শটি (ডেভ আব্রাহাম সহ) প্রয়োগ করে যে ডোমেনটি প্রয়োগ হয় তার বাইরেও এবং এটি সমস্ত std::string প্যারামিটারগুলিতে প্রয়োগ করার জন্য সহজ করে তোলে - সর্বদাstd::string মান দ্বারা পাস করা কোনও এবং সমস্ত স্বেচ্ছাচারিত পরামিতি এবং অ্যাপ্লিকেশনগুলির জন্য "সেরা অনুশীলন" নয় কারণ এইগুলি অপ্টিমাইজেশন আলোচনা / নিবন্ধগুলি কেবলমাত্র একটি সীমিত ক্ষেত্রে ক্ষেত্রে প্রয়োগের উপর দৃষ্টি নিবদ্ধ করে ।

আপনি যদি কোনও মান ফিরিয়ে দিচ্ছেন, প্যারামিটারটি পরিবর্তন করছেন বা মান নিচ্ছেন, তবে মান দ্বারা পাস করা ব্যয়বহুল অনুলিপি সংরক্ষণ করতে পারে এবং সিনট্যাক্টিক্যাল সুবিধাদি সরবরাহ করতে পারে।

সর্বদা হিসাবে, কনস্ট্যান্ড রেফারেন্স দিয়ে যাওয়ার সময় অনুলিপি সংরক্ষণ করে যখন আপনার কোনও অনুলিপি প্রয়োজন নেই

এখন নির্দিষ্ট উদাহরণে:

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

যদি স্ট্যাকের আকারটি উদ্বেগজনক হয় (এবং ধরে নিলে এটি ইনলাইনড / অপ্টিমাইজড নয়), return_val+ inval> return_val- আইওউ, পিক স্ট্যাকের ব্যবহার এখানে মান দ্বারা পাস করে হ্রাস করা যেতে পারে (দ্রষ্টব্য: ABIs এর ওভারসিম্প্লিফিকেশন)। এদিকে, কনস্ট্যান্ড রেফারেন্স দিয়ে পাস করা অপ্টিমাইজেশন অক্ষম করতে পারে। এখানে প্রাথমিক কারণটি হ'ল স্ট্যাক বৃদ্ধি এড়ানো নয়, তবে এটি প্রযোজ্য যেখানে অপ্টিমাইজেশন করা যায় তা নিশ্চিত করা ।

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


3
স্ট্যাক ব্যবহারে, আদর্শ এবিআই কোনও স্ট্যাকের ব্যবহার ছাড়াই একটি রেজিস্টারে একটি একক রেফারেন্স পাস করবে।
আহকক্স

63

এটি সংকলকের বাস্তবায়নের উপর অত্যন্ত নির্ভর করে।

তবে এটি আপনি কী ব্যবহার করেন তার উপরও নির্ভর করে।

পরবর্তী ফাংশন বিবেচনা করা যাক:

bool foo1( const std::string v )
{
  return v.empty();
}
bool foo2( const std::string & v )
{
  return v.empty();
}

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

আমার পিসিতে, g ++ 4.6.1 ব্যবহার করে আমি এই ফলাফলগুলি পেয়েছি:

  • রেফারেন্স অনুসারে পরিবর্তনশীল: 1000000000 পুনরাবৃত্তি -> সময় কেটে গেছে: 2.25912 সেকেন্ড
  • মান অনুসারে পরিবর্তনশীল: 1000000000 পুনরাবৃত্তি -> সময় কেটে গেছে: 27.2259 সেকেন্ড
  • রেফারেন্স দ্বারা আক্ষরিক: 100000000 পুনরাবৃত্তি -> সময় কেটে গেছে: 9.10319 সেকেন্ড
  • আক্ষরিক মান অনুসারে: 100000000 পুনরাবৃত্তি -> সময় কেটে গেছে: 8.62659 সেকেন্ড

4
আরও বেশি প্রাসঙ্গিক যা ফাংশনটির অভ্যন্তরে ঘটছে তা : যদি কোনও রেফারেন্স সহ বলা হয়, তবে কি অভ্যন্তরীণভাবে একটি অনুলিপি তৈরি করা দরকার যা মান দিয়ে যাওয়ার সময় বাদ দেওয়া যায় ?
বাম দিকের বাইরে

1
হ্যাঁ, অবশ্যই আমার অনুমান যে উভয় ফাংশন ঠিক একই জিনিস করছে same
BЈовић

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

3
আমার কাছে "এটি আপনি ফাংশনের ভিতরে কী করেন তার উপর নির্ভর করে" এটি হ'ল খারাপ নকশা - যেহেতু আপনি কার্যকারিতার ইন্টার্নালগুলিতে ফাংশনের স্বাক্ষরটি ভিত্তি করছেন।
হ্যান্স ওলসন

1
টাইপ হতে পারে তবে শেষ দুটি আক্ষরিক সময় 10x কম লুপ রয়েছে।
ট্যাঙ্কোরস্যামশ

54

সংক্ষিপ্ত উত্তর: না! দীর্ঘ উত্তর:

  • আপনি যদি স্ট্রিংটি সংশোধন না করেন (ট্রিট কেবল পঠনযোগ্য হিসাবে থাকে) তবে এটি পাস করুন const ref&
    (এটি const ref&কার্যকরভাবে ব্যবহৃত ফাংশনটি কার্যকর করার সময় অবশ্যই সুযোগের মধ্যে থাকতে হবে)
  • আপনি যদি এটি সংশোধন করার পরিকল্পনা করেন বা আপনি জানেন যে এটি সুযোগ (থ্রেড) থেকে বেরিয়ে আসবে , এ হিসাবে এটি পাস করুন value, const ref&আপনার ফাংশন বডিটির অভ্যন্তর অনুলিপি করবেন না ।

একটি পোস্ট ছিল cpp-next.com নামক "চান গতি, মান পাস!" । টিএল; ডিআর:

গাইডলাইন : আপনার ফাংশন যুক্তি অনুলিপি করবেন না। পরিবর্তে, তাদের মান দ্বারা পাস এবং সংকলক অনুলিপি করতে দিন।

^ এর অনুবাদ

আপনার ফাংশন আর্গুমেন্টগুলি অনুলিপি করবেন না --- এর অর্থ: আপনি যদি অভ্যন্তরীণ ভেরিয়েবলে অনুলিপি করে যুক্তির মানটি সংশোধন করার পরিকল্পনা করেন তবে পরিবর্তে একটি মান যুক্তি ব্যবহার করুন

সুতরাং, এটি করবেন না :

std::string function(const std::string& aString){
    auto vString(aString);
    vString.clear();
    return vString;
}

এটি কর :

std::string function(std::string aString){
    aString.clear();
    return aString;
}

আপনার ফাংশন বডিতে যখন আর্গুমেন্টের মানটি পরিবর্তন করতে হবে।

ফাংশন বডিটিতে আপনি কীভাবে যুক্তিটি ব্যবহার করার পরিকল্পনা করছেন সে সম্পর্কে আপনাকে সচেতন হওয়া দরকার। কেবল পঠনযোগ্য বা না ... এবং যদি এটি সুযোগের মধ্যে থাকে।


2
আপনি কিছু ক্ষেত্রে রেফারেন্স দিয়ে যাওয়ার পরামর্শ দিচ্ছেন, তবে আপনি এমন গাইডলাইনটির প্রতি নির্দেশ দিন যা সর্বদা মান অনুসারে অগ্রসর হওয়ার পরামর্শ দেয়।
কিথ থম্পসন

3
@ কিথথম্পসন আপনার ফাংশন যুক্তি অনুলিপি করবেন না। এর অর্থ const ref&এটি পরিবর্তন করতে কোনও অভ্যন্তরীণ ভেরিয়েবলে অনুলিপি করে না। আপনার যদি এটি সংশোধন করা দরকার ... প্যারামিটারটিকে একটি মান করুন। এটি আমার অ-ইংরাজী কথা বলার জন্য নয় বরং স্পষ্ট।
কোডআংগ্রি

5
@ কিথথম্পসন গাইডলাইনের উদ্ধৃতি (আপনার ফাংশন যুক্তিগুলি অনুলিপি করবেন না Instead পরিবর্তে, মান হিসাবে এটি পাস করুন এবং সংকলকটি অনুলিপিটি করতে দিন)) পৃষ্ঠাটি থেকে কপি করা হয়েছে । যদি এটি যথেষ্ট পরিষ্কার না হয় তবে আমি সহায়তা করতে পারি না। আমি সর্বোত্তম পছন্দগুলি করতে সংকলকদের সম্পূর্ণ বিশ্বাস করি না। আমি বরং ফাংশন আর্গুমেন্টগুলি যেভাবে সংজ্ঞায়িত করব তাতে আমার উদ্দেশ্য সম্পর্কে খুব স্পষ্ট থাকব। # 1 যদি এটি কেবল পঠনযোগ্য হয় তবে এটি একটি const ref&। # 2 যদি আমার এটি লেখার প্রয়োজন হয় বা আমি জানি এটি সুযোগের বাইরে চলে যায় ... আমি একটি মান ব্যবহার করি। # 3 যদি আমার মূল মানটি পরিবর্তন করতে হয় তবে আমি পাশ দিয়ে যাব ref&। # 4 আমি pointers *যদি যুক্তিটি optionচ্ছিক হয় তবে আমি এটি ব্যবহার করতে nullptrপারি।
কোডঅ্যানগ্রি

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

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

43

আপনার যদি সত্যই কোনও অনুলিপি না লাগে তবে এটি নেওয়া এখনও যুক্তিসঙ্গত const &। উদাহরণ স্বরূপ:

bool isprint(std::string const &s) {
    return all_of(begin(s),end(s),(bool(*)(char))isprint);
}

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

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


সংক্ষেপে, সি ++ 11 সত্যই কপির এলিজেনে বিশ্বাস করে না এমন লোকদের ব্যতীত এই ক্ষেত্রে আসলে কিছুই পরিবর্তন করে না।


2
মুভ কনস্ট্রাক্টরগুলি সাধারণত এর সাথে প্রয়োগ করা হয় noexcept, তবে অনুলিপি নির্মাণকারীরা অবশ্যই তা করেন না।
বাম দিকের বাইরে

25

প্রায়।

সি ++ 17 এ আমাদের রয়েছে basic_string_view<?>, যা আমাদেরকে std::string const&পরামিতিগুলির জন্য মূলত একটি সংকীর্ণ ব্যবহারের ক্ষেত্রে নামিয়ে আনে ।

পদক্ষেপের অস্তিত্বের জন্য একটি ব্যবহারের কেস কেটে গেছে std::string const&- আপনি যদি প্যারামিটারটি সংরক্ষণের পরিকল্পনা করে থাকেন তবে std::stringমান দ্বারা মূল্য নেওয়া আরও অনুকূল, কারণ আপনি moveপ্যারামিটারের বাইরে যেতে পারেন ।

যদি কেউ আপনার ফাংশনটিকে কাঁচা সি দিয়ে ডেকে থাকে তার "string"অর্থ এই ক্ষেত্রে কেবল std::stringদুটি std::string const&ক্ষেত্রে বিপরীতে কেবলমাত্র একটি বাফার বরাদ্দ করা হয় ।

তবে, আপনি যদি অনুলিপি তৈরি করতে চান না, তবে নেওয়া std::string const&C ++ 14 এ এখনও কার্যকর।

এর মাধ্যমে std::string_view, আপনি যতক্ষণ না '\0'সিআই -স্টাইল- নির্ধারিত চরিত্রের বাফারগুলি প্রত্যাশা করে এমন একটি এপিআই-তে স্ট্রিংটি পাস করছেন না , আপনি std::stringকোনও বরাদ্দের ঝুঁকি না নিয়ে আরও দক্ষতার সাথে কার্যকারিতা পেতে পারেন। কোনও কাঁচা সি স্ট্রিং এমনকি std::string_viewকোনও বরাদ্দ বা চরিত্র অনুলিপি ব্যতীত রূপান্তরিত হতে পারে ।

এই মুহুর্তে, std::string const&আপনি যখন হোলসাল তথ্যটি অনুলিপি করছেন না, এবং সি-স্টাইলের এপিআইতে যাচ্ছেন যা নাল টার্মিনেটেড বাফারকে প্রত্যাশা করে এবং এর জন্য আপনার উচ্চ স্তরের স্ট্রিং ফাংশনগুলির প্রয়োজন হবে তখন এর std::stringজন্য ব্যবহার। বাস্তবে, এটি প্রয়োজনীয়তার একটি বিরল সেট।


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

1
@ ফিশ 2000 স্পষ্ট হওয়ার জন্য std::string, আধিপত্য বজায় রাখার জন্য আপনার কেবল কিছু প্রয়োজনীয়তার প্রয়োজন নেই তবে সেগুলির সমস্ত প্রয়োজন । এর মধ্যে যে কোনও একটি বা দু'টি হ'ল, আমি স্বীকার করি, সাধারণ। হতে পারে আপনার সাধারণত 3 টি প্রয়োজন (যেমন আপনি কোন
সিআই এপিআইয়ের কাছে পাইকারিভাবে

@ ইয়াক্ক-অ্যাডামনেভ্র্যামন্ট এটি একটি ওয়াইএমএমভি জিনিস - তবে আপনি যদি পসিক্স, বা অন্য এপিআই-এর বিরুদ্ধে প্রোগ্রামিং করছেন তবে সি-স্ট্রিং শব্দার্থক যেমন সর্বনিম্ন সাধারণ ডিনোমিনেটর, এটি ঘন ঘন ব্যবহারের বিষয়। আমার সত্যই বলা উচিত যা আমি পছন্দ করি std::string_view- যেমন আপনি উল্লেখ করেছেন যে, "একটি কাঁচা সি স্ট্রিং এমনকি কোনও বরাদ্দ বা চরিত্র অনুলিপি ছাড়াই একটি স্ট্যান্ড :: স্ট্রিং_ভিউতে রূপান্তরিত করা যেতে পারে" যা তাদের প্রসঙ্গে সি ++ ব্যবহার করছে তাদের মনে রাখার মতো কিছু যেমন এপিআই ব্যবহার, সত্যিই।
fish2000

1
@ ফিশ 2000 "'কোনও কাঁচা সি স্ট্রিং এমনকি কোনও বরাদ্দ বা চরিত্রের অনুলিপি ছাড়াই একটি এসটিডি :: স্ট্রিং_ভিউতে রূপান্তরিত হতে পারে যা মনে রাখার মতো কিছু" " প্রকৃতপক্ষে, তবে এটি সবচেয়ে ভাল অংশটি ছেড়ে দেয় - কাঁচা স্ট্রিংটি একটি স্ট্রিং আক্ষরিক, এমনকি এটি রানটাইম স্ট্রেনের প্রয়োজন হয় না () !
ডন হ্যাচ

17

std::stringনয় প্লেইন প্রাচীন ডেটা (POD) , এবং তার কাঁচা আকার সর্বাধিক প্রাসঙ্গিক জিনিস কি কখনো নয়। উদাহরণস্বরূপ, আপনি যদি স্ট্রিংয়ে পাস করেন যা এসএসওর দৈর্ঘ্যের aboveর্ধ্বে এবং গাদাতে বরাদ্দ দেওয়া হয়, তবে আমি অনুলিপি নির্মাণকারীকে এসএসও স্টোরেজ অনুলিপি না করার আশা করব।

কারণ এটির প্রস্তাবিত কারণ invalহ'ল যুক্তি প্রকাশ থেকে তৈরি করা হয়েছে, এবং যথাযথ হিসাবে সর্বদা সরানো বা অনুলিপি করা হয় - কার্যকারিতা ক্ষতি হয় না, ধরে নিই যে আপনার পক্ষে যুক্তির মালিকানা প্রয়োজন। যদি আপনি তা না করেন, তবে একটি constরেফারেন্স এখনও যাওয়ার আরও ভাল উপায় হতে পারে।


2
অনুলিপিটি সম্পর্কে অনুলিপিযোগ্য বিষয় হ'ল এসএসও এটি ব্যবহার না করে তবে চিন্তিত হওয়ার পক্ষে যথেষ্ট নয়। সম্ভবত সঠিক, আমি এটি সত্য কিনা তা
খতিয়ে

3
@ বেঞ্জ: পুরাতন মন্তব্য আমি জানি, তবে এসএসও যদি যথেষ্ট ছোট হয় তবে নিঃশর্তভাবে এটিকে অনুলিপি করা শর্তযুক্ত শাখা করার চেয়ে দ্রুত। উদাহরণস্বরূপ, by৪ বাইট একটি ক্যাশে লাইন এবং সময়ের সত্যই তুচ্ছ পরিমাণে অনুলিপি করা যায়। সম্ভবত 8 টি চক্র বা x86_64 এর চেয়ে কম।
জ্যান লিংস

এসএসও অনুলিপিটি অনুলিপি না করেও, std::string<>32 টি বাইট যা স্ট্যাক থেকে বরাদ্দ করা হয়, তার মধ্যে 16 টি আরম্ভ করা দরকার। এটি রেফারেন্সের জন্য বরাদ্দকৃত এবং প্রাথমিক করা মাত্র 8 বাইটের সাথে তুলনা করুন: এটি সিপিইউ কাজের পরিমাণের দ্বিগুণ এবং এটি অন্যান্য ডেটাতে উপলভ্য হবে না এমন ক্যাশে স্পেসের চেয়ে চারগুণ বেশি সময় নেয়।
মাস্টার

ওহ, এবং আমি রেজিস্টারগুলিতে ফাংশন যুক্তিগুলি পাস করার বিষয়ে কথা বলতে ভুলে গেছি; এটি শেষ
কলির

16

আমি এই প্রশ্নটি থেকে উত্তর এখানে অনুলিপি / আটকানো করেছি , এবং এই প্রশ্নের সাথে মানানসই নাম এবং বানান পরিবর্তন করেছি।

যা জিজ্ঞাসা করা হচ্ছে তা পরিমাপ করার কোড এখানে রয়েছে:

#include <iostream>

struct string
{
    string() {}
    string(const string&) {std::cout << "string(const string&)\n";}
    string& operator=(const string&) {std::cout << "string& operator=(const string&)\n";return *this;}
#if (__has_feature(cxx_rvalue_references))
    string(string&&) {std::cout << "string(string&&)\n";}
    string& operator=(string&&) {std::cout << "string& operator=(string&&)\n";return *this;}
#endif

};

#if PROCESS == 1

string
do_something(string inval)
{
    // do stuff
    return inval;
}

#elif PROCESS == 2

string
do_something(const string& inval)
{
    string return_val = inval;
    // do stuff
    return return_val; 
}

#if (__has_feature(cxx_rvalue_references))

string
do_something(string&& inval)
{
    // do stuff
    return std::move(inval);
}

#endif

#endif

string source() {return string();}

int main()
{
    std::cout << "do_something with lvalue:\n\n";
    string x;
    string t = do_something(x);
#if (__has_feature(cxx_rvalue_references))
    std::cout << "\ndo_something with xvalue:\n\n";
    string u = do_something(std::move(x));
#endif
    std::cout << "\ndo_something with prvalue:\n\n";
    string v = do_something(source());
}

আমার জন্য এই ফলাফলগুলি:

$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=1 test.cpp
$ a.out
do_something with lvalue:

string(const string&)
string(string&&)

do_something with xvalue:

string(string&&)
string(string&&)

do_something with prvalue:

string(string&&)
$ clang++ -std=c++11 -stdlib=libc++ -DPROCESS=2 test.cpp
$ a.out
do_something with lvalue:

string(const string&)

do_something with xvalue:

string(string&&)

do_something with prvalue:

string(string&&)

নীচের টেবিলটি আমার ফলাফলগুলির সংক্ষিপ্তসার করেছে (ঝনঝন -std = c ++ 11 ব্যবহার করে)। প্রথম সংখ্যাটি হ'ল অনুলিপি নির্মাণের সংখ্যা এবং দ্বিতীয় সংখ্যাটি হ'ল মুভ নির্মাণের সংখ্যা:

+----+--------+--------+---------+
|    | lvalue | xvalue | prvalue |
+----+--------+--------+---------+
| p1 |  1/1   |  0/2   |   0/1   |
+----+--------+--------+---------+
| p2 |  1/0   |  0/1   |   0/1   |
+----+--------+--------+---------+

পাস-বাই-ভ্যালু সলিউশনের জন্য কেবল একটি ওভারলোড প্রয়োজন তবে ল্যাভালু এবং এক্সভালিউগুলি পাস করার সময় একটি অতিরিক্ত সরানো নির্মাণের জন্য ব্যয় হয়। এটি কোনও প্রদত্ত পরিস্থিতির জন্য গ্রহণযোগ্য হতে পারে বা নাও পারে। উভয় সমাধানের সুবিধা এবং অসুবিধা রয়েছে।


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

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

পরীক্ষাগুলি সম্পাদনের আগে আপনার সম্ভবত কোডটি অপ্টিমাইজ করা উচিত ...
প্যারাম্যাগনেটিক ক্রোস্যান্ট

3
@ দ্য পারম্যাগনেটিক ক্রোস্যান্ট: আপনি কি আলাদা ফলাফল পেয়েছেন? যদি তা হয় তবে কোন কমান্ড লাইনের যুক্তিগুলির সাথে কি সংকলকটি ব্যবহার করছেন?
হাওয়ার্ড হিনান্ট

14

const std::string&প্যারামিটার ধরণের হিসাবে সুপারিশ করার জন্য হার্জার স্ট্রোস্ট্রপ সহ ভেষজ সুটার এখনও রেকর্ডে রয়েছে ; দেখতে https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rf-in

এখানে অন্য উত্তরের কোনওটিতেই উল্লেখযোগ্য একটি সমস্যা নেই: আপনি যদি কোনও const std::string&প্যারামিটারে একটি স্ট্রিং আক্ষরিক অর্থে প্রদান করেন তবে এটি একটি অস্থায়ী স্ট্রিংয়ের রেফারেন্সটি পাঠিয়ে দেবে, যা আক্ষরিক চরিত্রগুলি ধরে রাখতে অন-ফ্লাইয়ে তৈরি হয়েছিল। তারপরে আপনি যদি সেই রেফারেন্সটি সংরক্ষণ করেন, অস্থায়ী স্ট্রিংটি বাতিল হয়ে গেলে এটি অবৈধ। নিরাপদ থাকতে, আপনাকে অবশ্যই একটি অনুলিপি সংরক্ষণ করতে হবে , রেফারেন্সটি নয়। সমস্যাটি স্ট্রিং লিটারালগুলি const char[N]প্রকারের থেকে প্রচারের প্রয়োজন হতে শুরু করে std::string

নীচের কোডটি একটি ক্ষুদ্র দক্ষতার বিকল্পের পাশাপাশি সমস্যা এবং কর্মক্ষেত্রের চিত্র তুলে ধরেছে - একটি const char*পদ্ধতির সাথে ওভারলোডিং যেমন বর্ণনা করা হয়েছে সেখানে কি সি ++ তে রেফারেন্স হিসাবে একটি স্ট্রিং আক্ষরিক পাস করার উপায় রয়েছে ?

(দ্রষ্টব্য: সটার এবং স্ট্রাউট গ্রুপ পরামর্শ দেয় যে আপনি যদি স্ট্রিংয়ের অনুলিপি রাখেন তবে একটি অ্যান্ড ওভার প্যারামিটার এবং ওভার স্ট্র্যাড :: মুভ () এটি দিয়ে একটি ওভারলোডেড ফাংশনও সরবরাহ করুন))

#include <string>
#include <iostream>
class WidgetBadRef {
public:
    WidgetBadRef(const std::string& s) : myStrRef(s)  // copy the reference...
    {}

    const std::string& myStrRef;    // might be a reference to a temporary (oops!)
};

class WidgetSafeCopy {
public:
    WidgetSafeCopy(const std::string& s) : myStrCopy(s)
            // constructor for string references; copy the string
    {std::cout << "const std::string& constructor\n";}

    WidgetSafeCopy(const char* cs) : myStrCopy(cs)
            // constructor for string literals (and char arrays);
            // for minor efficiency only;
            // create the std::string directly from the chars
    {std::cout << "const char * constructor\n";}

    const std::string myStrCopy;    // save a copy, not a reference!
};

int main() {
    WidgetBadRef w1("First string");
    WidgetSafeCopy w2("Second string"); // uses the const char* constructor, no temp string
    WidgetSafeCopy w3(w2.myStrCopy);    // uses the String reference constructor
    std::cout << w1.myStrRef << "\n";   // garbage out
    std::cout << w2.myStrCopy << "\n";  // OK
    std::cout << w3.myStrCopy << "\n";  // OK
}

আউটপুট:

const char * constructor
const std::string& constructor

Second string
Second string

এটি একটি আলাদা সমস্যা এবং উইজেটব্যাডরেফের ভুল হওয়ার জন্য কনস্ট এবং প্যারামিটারের দরকার নেই। প্রশ্নটি হ'ল উইজেটসেফকপি যদি কেবল একটি স্ট্রিং প্যারামিটার নেয় তবে এটি ধীর হবে? (আমি মনে করি সদস্যের অনুলিপিটি অনুলিপি করা
স্পষ্টভাবে

নোট করুন যে T&&সর্বদা সর্বজনীন রেফারেন্স নয়; প্রকৃতপক্ষে, std::string&&সর্বদা একটি নিয়মিত রেফারেন্স এবং সর্বজনীন রেফারেন্স হবে, কারণ কোনও ধরণের ছাড় ছাড়াই হয় না । সুতরাং, স্ট্রস্ট্রুপ এবং সটারের পরামর্শ মায়ারদের সাথে বিরোধী নয়।
জাস্টিন সময় - মনিকা 22

@ জাস্টিনটাইম: আপনাকে ধন্যবাদ; আমি ভুল চূড়ান্ত বাক্যটি দাবি করে সরিয়ে দিয়েছিলাম, বাস্তবে, এই স্টাড :: স্ট্রিং ও& এর সর্বজনীন রেফারেন্স হবে।
সার্কেলপিআই 143

@ বৃত্তপরি 314 আপনাকে স্বাগতম এটি তৈরি করা একটি সহজ মিশ্রণ, এটি প্রদত্ত যে কোনও T&&ছাড়ের সার্বজনীন রেফারেন্স বা অ-ছাড়িয়ে দেওয়া মূল্যের রেফারেন্স কিনা তা কখনও কখনও বিভ্রান্ত হতে পারে ; যদি তারা সর্বজনীন রেফারেন্সের জন্য একটি আলাদা প্রতীক (যেমন &&&, &এবং এর সংমিশ্রণ হিসাবে &&) উপস্থাপন করেন তবে সম্ভবত এটি আরও পরিষ্কার হবে but তবে এটি সম্ভবত নিরীহ দেখায়।
জাস্টিন সময় - মনিকা

8

আইএমও এর জন্য সি ++ রেফারেন্স ব্যবহার std::stringকরা একটি দ্রুত এবং সংক্ষিপ্ত স্থানীয় অপ্টিমাইজেশন, যখন মান দ্বারা পাস করা আরও ভাল বিশ্বব্যাপী অপ্টিমাইজেশান হতে পারে (বা না)।

সুতরাং উত্তরটি: এটি পরিস্থিতির উপর নির্ভর করে:

  1. আপনি যদি সমস্ত কোড বাইরে থেকে অভ্যন্তরীণ ফাংশনগুলিতে লিখেন তবে কোডটি কী করে তা আপনি জানেন, আপনি রেফারেন্সটি ব্যবহার করতে পারেন const std::string &
  2. আপনি যদি লাইব্রেরি কোডটি লিখেন বা স্ট্রিংগুলি পাস করা ভারী লাইব্রেরি কোড ব্যবহার করেন তবে আপনি std::stringঅনুলিপি নির্মাণকারী আচরণের উপর বিশ্বাস রেখে বিশ্বব্যাপী আরও বেশি লাভ করতে পারেন ।

6

দেখুন "ঔষধি Sutter" আধুনিক সি ++ স্টাইল এর বুনিয়াদি! এসেনশিয়ালস ফিরে যান " । অন্যান্য বিষয় মধ্যে, তিনি প্যারামিটার ক্ষণস্থায়ী পরামর্শ যা অতীতে দেওয়া হয়েছে, এবং নতুন ধারণা যে সি ++ 11 এসে বিশেষভাবে এ দেখায় রিভিউ মান দ্বারা স্ট্রিং পাস করার ধারণা।

স্লাইড 24

মানদণ্ডগুলি দেখায় যে std::stringমান দ্বারা পাস করার ফলে, ফাংশন যেভাবেই এটি অনুলিপি করবে, উল্লেখযোগ্যভাবে ধীর হতে পারে!

এটি কারণ আপনি সর্বদা একটি সম্পূর্ণ অনুলিপি তৈরি করতে বাধ্য করছেন (এবং তারপরে স্থানান্তরিত করুন), const&সংস্করণটি পুরানো স্ট্রিং আপডেট করবে যা ইতিমধ্যে বরাদ্দকৃত বাফারটিকে পুনরায় ব্যবহার করতে পারে।

তার স্লাইড 27 দেখুন: "সেট" ফাংশনগুলির জন্য, বিকল্প 1টি সর্বদা যেমন ছিল তেমন। অপশন 2 যথাযথ রেফারেন্সের জন্য একটি ওভারলোড যুক্ত করে, তবে একাধিক পরামিতি থাকলে এটি একটি সম্মিলিত বিস্ফোরণ দেয়।

এটি কেবলমাত্র "সিঙ্ক" পরামিতিগুলির জন্য যেখানে স্ট্রিং তৈরি করতে হবে (এর বিদ্যমান মানটি পরিবর্তন করা উচিত নয়) যে পাস-বাই-ভ্যালু ট্রিকটি বৈধ। এটি হ'ল, এমন কনস্ট্রাক্টর যেখানে প্যারামিটারটি ম্যাচিং টাইপের সদস্যটিকে সরাসরি আরম্ভ করে।

আপনি যদি এই নিয়ে উদ্বিগ্ন হতে কত গভীর হতে পারেন তা জানতে চাইলে নিকোলাই জোসুতিসের উপস্থাপনা এবং সেই সাথে ( "পারফেক্ট - সম্পন্ন!" N এর আগের সংস্করণটির সাথে ত্রুটি খুঁজে পাওয়ার পরে একবার দেখুন Ever কখনও হয়েছে?)


এটি স্ট্যান্ডার্ড গাইডলাইনসে ⧺F.15 হিসাবে সংক্ষিপ্তসারিত হয় ।


3

@ জডিডুগোসজে মন্তব্যগুলিতে যেমন উল্লেখ করেছেন, হার্ব আরেকটি পরামর্শ দিয়েছেন (পরে?) কথা বলার জন্য, এখান থেকে মোটামুটি দেখুন: https://youtu.be/xnqTKD8uD64?t=54m50s

তার পরামর্শটি কেবলমাত্র এমন ফাংশনের জন্য মান পরামিতিগুলি ব্যবহার করে fযা এই ডুবে আর্গুমেন্টগুলি থেকে আপনি নির্মাণ সরিয়ে নিয়ে যাবেন বলে ধরে নেওয়া যায় ink

এই সাধারণ পদ্ধতিটি fযথাক্রমে ল্যাভেলু এবং রাল্যু যুক্তিগুলির অনুকূলতর প্রয়োগের তুলনায় লভালু এবং মূল্যমান উভয় যুক্তির জন্য একটি মুভ কনস্ট্রাক্টরের ওভারহেড যুক্ত করে । কেন এটি হয় তা দেখার জন্য, ধরুন fএকটি মান প্যারামিটার লাগে, যেখানে Tকিছু অনুলিপি থাকে এবং গঠনমূলক ধরণের স্থানান্তরিত হয়:

void f(T x) {
  T y{std::move(x)};
}

fলভ্যালু আর্গুমেন্টের সাথে কল করার ফলে একটি অনুলিপি নির্মাণকারীকে নির্মাণের জন্য ডাকা হবে xএবং একটি মুভ কনস্ট্রাক্টরকে নির্মাণের জন্য ডাকা হবে y। অন্যদিকে, fকোনও মূল্যের আর্গুমেন্টের সাথে কল করার ফলে একজন মুভ কনস্ট্রাক্টরকে নির্মাণের জন্য ডেকে আনতে হবে xএবং অন্য একটি মুভ কনস্ট্রাক্টরকে নির্মাণের জন্য ডাকা হবে y

সাধারণভাবে, fলভালু আর্গুমেন্টের সর্বোত্তম বাস্তবায়ন নিম্নরূপ:

void f(const T& x) {
  T y{x};
}

এই ক্ষেত্রে, কেবলমাত্র একটি অনুলিপি নির্মাণকারীকে নির্মাণ করতে বলা হয় yfযথাযথ আর্গুমেন্টের সর্বোত্তম বাস্তবায়নটি আবার সাধারণভাবে নিম্নরূপ:

void f(T&& x) {
  T y{std::move(x)};
}

এই ক্ষেত্রে, শুধুমাত্র একটি মুভ কনস্ট্রাক্টরকে কনস্ট্রাক্ট করার জন্য ডাকা হয় y

সুতরাং একটি বুদ্ধিমান সমঝোতা হ'ল একটি মান প্যারামিটার গ্রহণ করা এবং সর্বোত্তম বাস্তবায়নের ক্ষেত্রে লভালু বা মূল্যবান যুক্তিগুলির জন্য একটি অতিরিক্ত পদক্ষেপের কনস্ট্রাক্টর কল করা, যা হার্বের আলোচনায় দেওয়া পরামর্শও।

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

void f(T x) {
  T y{...};
  ...
  y = std::move(x);
}

এই ক্ষেত্রে, একটি অনুলিপি নির্মাণের জন্য একটি মূল্যবান আর্গুমেন্টের জন্য একটি অনুলিপি নির্মাণ এবং একটি মুভ নির্মাণ এবং মূল্যের আর্গুমেন্টের জন্য সরানো অ্যাসাইনমেন্ট রয়েছে। লভ্যালু আর্গুমেন্টের জন্য সর্বাধিক অনুকূল কেসটি হ'ল:

void f(const T& x) {
  T y{...};
  ...
  y = x;
}

এটি কেবলমাত্র একটি অ্যাসাইনমেন্টে ফোটে, যা কপিরাইট কনস্ট্রাক্টর প্লাস-বাই-ভ্যালু পদ্ধতির জন্য প্রয়োজনীয় মুভ অ্যাসাইনমেন্টের চেয়ে সম্ভাব্য অনেক কম। এর কারণ হ'ল অ্যাসাইনমেন্টটি বিদ্যমান বরাদ্দকৃত মেমরিটিকে পুনরায় ব্যবহার করতে পারে yএবং তাই (ডি) বরাদ্দকে আটকাতে পারে, তবে অনুলিপি নির্মাণকারী সাধারণত মেমরি বরাদ্দ করে।

কোনও মূল্যায়িত যুক্তির জন্য সর্বাধিক অনুকূল বাস্তবায়নের জন্য fএকটি অনুলিপিটি ফর্মটি ধারণ করে:

void f(T&& x) {
  T y{...};
  ...
  y = std::move(x);
}

সুতরাং, এই ক্ষেত্রে কেবল একটি সরানো কার্য এর সংস্করণে কোনও মূল্য পাস করাতে কনস্টের fরেফারেন্স লাগে কেবল স্থানান্তরের অ্যাসাইনমেন্টের পরিবর্তে একটি অ্যাসাইনমেন্টের জন্য। তুলনামূলকভাবে বলতে গেলে, fসাধারণ প্রয়োগ হিসাবে এই ক্ষেত্রে একটি দৃ const় রেফারেন্স নেওয়ার সংস্করণটি পছন্দনীয়।

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


আমার নতুন উত্তরে ভেষজ সুটারের অনুসন্ধানগুলি দেখুন: কেবলমাত্র তখনই করুন যখন আপনি নির্মাণকে সরান, বরাদ্দ বরাদ্দ করবেন না।
জেডিগোসস

1
@ জেডিগোগস, হার্বের আলোচনার পয়েন্টারটির জন্য ধন্যবাদ, আমি কেবল এটি দেখেছি এবং আমার উত্তরটিকে পুরোপুরি সংশোধন করেছি। আমি (পদক্ষেপ) বরাদ্দ পরামর্শ সম্পর্কে অবগত ছিল না।
টন ভ্যান ড্যান হিউভেল


1

সমস্যাটি হ'ল "কনস্ট" হ'ল নন-দানাদার কোয়ালিফায়ার। সাধারণত "কনস্ট্রিং স্ট্রিং রেফ" বলতে যা বোঝায় তা হ'ল "এই স্ট্রিংটি সংশোধন করবেন না", "রেফারেন্স কাউন্টটি সংশোধন করবেন না"। সেখানে কেবল কোন উপায়, সি ++ এ, বলতে হয় যা সদস্যদের "const" হয়। তারা হয় সব হয়, বা তাদের কেউ নেই।

অর্ডার এই ভাষা বিষয়টি প্রায় হ্যাক করার জন্য, STL পারে "সি ()" আপনার উদাহরণে একটি পদক্ষেপ-শব্দার্থিক কপি করার অনুমতি প্রদান যাহাই হউক না কেন রেফারেন্স COUNT (চপল) ব্যাপারে সঙ্গে "const" অগ্রাহ্য, অ্যাশেজ পুনরুদ্ধারের। যতক্ষণ এটি সুনির্দিষ্টভাবে উল্লেখ করা হয়েছিল ততক্ষণ এটি ঠিক থাকবে।

যেহেতু এসটিএল নেই, আমার কাছে একটি স্ট্রিংয়ের একটি সংস্করণ রয়েছে যা রেফারেন্স কাউন্টারকে <> দূরে সরিয়ে কোনও কিছুকে শ্রেণিবিন্যাসে পরিবর্তনীয় করে তোলার কোনও উপায় নয়), এবং - দেখুন এবং দেখুন - আপনি সেন্টিমস্ট্রিংকে নির্বিঘ্নে রেফারেন্স হিসাবে পাস করতে পারেন, এবং কোনও ফুটা বা সমস্যা ছাড়াই, সারা দিন ধরে গভীর ফাংশনগুলিতে সেগুলির অনুলিপিগুলি তৈরি করুন।

যেহেতু সি ++ এখানে কোনও "ডাইরেক্টেড ক্লাস কনস্ট গ্রানুলারিটি" সরবরাহ করে না, তাই একটি ভাল স্পেসিফিকেশন লিখে একটি চকচকে নতুন "কনস্ট চলমান স্ট্রিং" (সেমিস্ট্রিং) অবজেক্ট তৈরি করা আমার দেখা সেরা সমাধান।


@ বেনভয়েগ হ্যাঁ ... ফেলে দেওয়ার পরিবর্তে এটি পরিবর্তনযোগ্য হওয়া উচিত ... তবে আপনি কোনও এসটিএল সদস্যকে পরিবর্তিত শ্রেণিতে পরিবর্তন করতে পারবেন না।
এরিক অ্যারোনস্টি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.