সি ++ এ কীভাবে "কোনও জিনিস ফেরত" দেবেন?


167

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

জাভাতে আমি সর্বদা "স্থানীয়" অবজেক্টের জন্য উল্লেখগুলি ফিরিয়ে দিতে পারি

public Thing calculateThing() {
    Thing thing = new Thing();
    // do calculations and modify thing
    return thing;
}

সি ++ তে অনুরূপ কিছু করার জন্য আমার কাছে 2 টি বিকল্প রয়েছে

(1) যখনই আমার কোনও বস্তুর "ফেরত" দরকার হয় আমি রেফারেন্সগুলি ব্যবহার করতে পারি

void calculateThing(Thing& thing) {
    // do calculations and modify thing
}

তারপরে এটি ব্যবহার করুন

Thing thing;
calculateThing(thing);

(২) অথবা আমি গতিশীলভাবে বরাদ্দকৃত অবজেক্টে একটি পয়েন্টার ফিরিয়ে দিতে পারি

Thing* calculateThing() {
    Thing* thing(new Thing());
    // do calculations and modify thing
    return thing;
}

তারপরে এটি ব্যবহার করুন

Thing* thing = calculateThing();
delete thing;

প্রথম পদ্ধতির সাহায্যে আমি ম্যানুয়ালি ম্যানুয়ালি মুক্ত করতে হবে না, তবে আমার কাছে এটি কোডটি পড়া কঠিন করে তোলে। দ্বিতীয় পদ্ধতির সমস্যাটি হ'ল, আমাকে মনে রাখতে হবে delete thing;, যা দেখতে খুব সুন্দর দেখাচ্ছে না। আমি অনুলিপি করা মানটি ফিরিয়ে দিতে চাই না কারণ এটি অদক্ষ (আমার মনে হয়), তাই এখানে প্রশ্নগুলি আসুন

  • তৃতীয় কোন সমাধান আছে (এর জন্য মানটির অনুলিপি লাগবে না)?
  • আমি যদি প্রথম সমাধানটিতে থাকি তবে কি কোনও সমস্যা আছে?
  • আমার দ্বিতীয় সমাধানটি কখন এবং কেন ব্যবহার করা উচিত?

32
প্রশ্নটি সুন্দরভাবে রাখার জন্য +1।
কাঙকান

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

উত্তর:


107

আমি অনুলিপি করা মানটি ফিরিয়ে দিতে চাই না কারণ এটি অদক্ষ

প্রমান কর.

আরভিও এবং এনআরভিও অনুসন্ধান করুন এবং সি ++ 0x মুভ-শব্দার্থক শব্দে। C ++ 03 এর বেশিরভাগ ক্ষেত্রেই, আপনার কোডটি কুৎসিত করার একটি আউট প্যারামিটার হ'ল একটি ভাল উপায় এবং সি ++ 0x এ আপনি আউট প্যারামিটারটি ব্যবহার করে নিজেকে আঘাত করতে চান।

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


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

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


10
@ ফুনেহেহে: কোনও কথা অনুমান করা হচ্ছে না, আপনার নিজের কোডটি প্রোফাইল করা উচিত এবং এটি বের করা উচিত। (ইঙ্গিত: না।) সংকলকগুলি খুব স্মার্ট, তারা যদি না থাকে তবে চারপাশে জিনিসগুলি অনুলিপি করতে সময় নষ্ট করবে না। এমনকি কোনও কিছুতে অনুলিপি করা হলেও, আপনার এখনও দ্রুত কোডের চেয়ে ভাল কোডের জন্য প্রচেষ্টা করা উচিত; গতি সমস্যা হয়ে গেলে ভাল কোডটি অনুকূলিতকরণ করা সহজ। আপনার কোনও ধারণা নেই এমন কোনও কিছুর জন্য কোড আপ আপ করার কোনও মানে নেই সমস্যা; বিশেষত যদি আপনি আসলে এটি ধীর করে দেন বা এটিকে থেকে কিছুই পান না। এবং আপনি যদি C ++ 0x ব্যবহার করেন তবে সরানো-শব্দার্থবিজ্ঞানগুলি এটি একটি নন-ইস্যু করে।
GManNickG

1
@ জিএমএন, রে: আরভিও: আসলে এটি কেবল সত্য যদি আপনার কলার এবং কলি একই সংকলন ইউনিটে ঘটে থাকে, যা বাস্তব বিশ্বে এটি বেশিরভাগ সময় নয়। সুতরাং, আপনি হতাশায় রয়েছেন যদি আপনার কোডটি সমস্ত পরীক্ষিত না হয় (তবে এটি সমস্তই একটি সংকলনের ইউনিটে থাকবে) বা আপনার কিছু লিঙ্ক-টাইম অপ্টিমাইজেশন রয়েছে (জিসিসি এটি কেবল 4.5 থেকে রয়েছে)।
অ্যালেক্স বি

2
@ অ্যালেক্স: অনুবাদকরা অনুবাদ ইউনিটগুলিতে অনুকূলকরণের ক্ষেত্রে আরও ভাল এবং ভাল হচ্ছেন better (ভিসি এখন বেশ কয়েকটি রিলিজের জন্য এটি করেন))
এসবিআই

9
@ অ্যালেক্স বি: এটি সম্পূর্ণ আবর্জনা। অনেক প্রচলিত কলিং কনভেনশনগুলি কলারকে বৃহত্তর রিটার্ন মানগুলির জন্য স্থান বরাদ্দের জন্য এবং তাদের নির্মাণের জন্য কলিকে দায়ী করে responsible আরভিও সুস্পষ্টভাবে লিঙ্ক টাইম অপ্টিমাইজেশন ছাড়াই সংকলন ইউনিট জুড়ে কাজ করে।
সিবি বেইলি

6
@ চারেলস, এটি যাচাই করার পরে এটি সঠিক বলে মনে হচ্ছে! আমি আমার স্পষ্টত ভুল তথ্যের বিবৃতি প্রত্যাহার করি।
অ্যালেক্স বি

41

কেবল বস্তুটি তৈরি করুন এবং এটি ফিরিয়ে দিন

Thing calculateThing() {
    Thing thing;
    // do calculations and modify thing
     return thing;
}

আমি মনে করি আপনি অপ্টিমাইজেশন সম্পর্কে ভুলে গেলে এবং কেবল পঠনযোগ্য কোডটি লিখে রাখলে আপনি নিজের পক্ষে একটি উপকার করবেন (তবে আপনাকে পরে প্রোফাইলার চালাতে হবে - তবে প্রাক-অনুকূলিতকরণ করবেন না)।


2
Thing thing();একটি স্থানীয় ফাংশন ঘোষণা করে এবং ফিরে আসে a Thing
স্বপ্নের

2
জিনিসটি () কোনও জিনিস ফিরিয়ে ফাংশন ঘোষণা করে। আপনার ফাংশন বডিটিতে কোনও থিং অবজেক্ট নির্মিত নেই।
সিবি বেইলি

@ ড্রিমল্যাক্স @ চার্লস @ জিএমান কিছুটা দেরীতে হলেও স্থির হয়েছে।
আমির রাছুম

এটি সি ++ 98 এ কীভাবে কাজ করে? আমি সিআইএনটি ইন্টারপ্রেটারে ত্রুটি পেয়েছি এবং ভাবছিলাম যে এটি সি ++ 98 বা নিজেই সিআইএনটির কারণে ...!
xcorat

16

কেবল এই জাতীয় কোনও বস্তু ফেরত দিন:

Thing calculateThing() 
{
   Thing thing();
   // do calculations and modify thing
   return thing;
}

এটি জিনিসগুলিতে অনুলিপি নির্মাণকারীকে অনুরোধ করবে, যাতে আপনি এটির নিজের প্রয়োগটি করতে পারেন। এটার মত:

Thing(const Thing& aThing) {}

এটি কিছুটা ধীর গতিতে পারফর্ম করতে পারে তবে এটি কোনও সমস্যা নয়।

হালনাগাদ

সংকলক সম্ভবত অনুলিপি নির্মাণকারীকে কলটি অনুকূল করে তুলবে, সুতরাং কোনও অতিরিক্ত ওভারহেড থাকবে না। (মতামতে নির্দেশিত স্বপ্নের মতো)


9
Thing thing();একটি স্থানীয় ফাংশন ঘোষনা করে একটি Thing, এছাড়াও, মানটি আপনার উপস্থাপিত ক্ষেত্রে অনুলিপি নির্মাণকারীকে বাদ দিতে সংকলককে অনুমতি দেয়; যে কোনও আধুনিক সংকলক সম্ভবত এটি করবে।
স্বপ্নের

1
অনুলিপি নির্মাণকারীকে কার্যকর করার জন্য আপনি একটি ভাল বিষয় নিয়ে এসেছেন, বিশেষত যদি গভীর অনুলিপি প্রয়োজন হয়।
mbadawi23

অনুলিপি নির্ধারণকারী সম্পর্কে স্পষ্টভাবে উল্লেখ করার জন্য +1, যদিও @ ড্রিমলাক্স বলেছেন যে সংকলকটি সম্ভবত অনুলিপি নির্মাণকারীকে সত্যিকারের প্রয়োজনীয় কল না এড়িয়ে ফাংশনগুলির জন্য রিটার্নিং কোডটিকে "অনুকূলিত" করবে ize
jose.angel.jimenez

2018 সালে, ভিএস 2017 তে, এটি মুভ কনস্ট্রাক্টরটি ব্যবহার করার চেষ্টা করছে। যদি মুভ কনস্ট্রাক্টর মুছে ফেলা হয় এবং কপি কনস্ট্রাক্টর না হয় তবে এটি সংকলন করবে না।
অ্যান্ড্রু

11

আপনি কি অটো_পিটারের মতো স্মার্ট পয়েন্টার (যদি জিনিসটি সত্যই বড় এবং ভারী বস্তু হয়) ব্যবহার করার চেষ্টা করেছিলেন:


std::auto_ptr<Thing> calculateThing()
{
  std::auto_ptr<Thing> thing(new Thing);
  // .. some calculations
  return thing;
}


// ...
{
  std::auto_ptr<Thing> thing = calculateThing();
  // working with thing

  // auto_ptr frees thing 
}

4
auto_ptrs অবচিত হয়; ব্যবহার shared_ptrবা unique_ptrপরিবর্তে।
এমবিরাডলি

এখানে কেবল এটি যুক্ত করতে চলেছি ... আমি বহু বছর ধরে সি ++ ব্যবহার করে আসছি, যদিও পেশাদারভাবে সি ++ দিয়ে নয়, ... আমি স্মার্ট পয়েন্টারগুলি আর ব্যবহার না করার চেষ্টা করার দৃ determined় সংকল্প নিয়েছি, তারা কেবল পরম গণ্ডগোলের কারণ এবং সমস্ত কারণ সৃষ্টি করে সমস্যা বিভিন্ন ধরণের, সত্যিই হয় না খুব দ্রুত কোড গতিতে সাহায্য। আমি বরং বরং কেবলমাত্র চারপাশের ডেটা অনুলিপি করতাম এবং নিজেই পয়েন্টারগুলি পরিচালনা করতাম, আরআইআইআই ব্যবহার করে। সুতরাং আমি পরামর্শ দিচ্ছি যে আপনি যদি পারেন তবে স্মার্ট পয়েন্টারগুলি এড়িয়ে চলুন।
অ্যান্ড্রু

8

কোনও অনুলিপি নির্মাণকারীকে ডাকা হচ্ছে কিনা তা নির্ধারণের একটি দ্রুত উপায় হ'ল আপনার শ্রেণীর অনুলিপি নির্মাণকারীকে লগিং যুক্ত করা:

MyClass::MyClass(const MyClass &other)
{
    std::cout << "Copy constructor was called" << std::endl;
}

MyClass someFunction()
{
    MyClass dummy;
    return dummy;
}

কল someFunction; "কপিরাইট কনস্ট্রাক্টররের" নাম্বারটি বলা হয়েছিল "যে লাইনগুলি আপনি পাবেন তা 0, 1 এবং 2 এর মধ্যে পরিবর্তিত হবে যদি আপনি কোনওটি না পান তবে আপনার সংকলকটি রিটার্ন মানটি (যা এটি করার অনুমতি দেওয়া হয়েছে) অনুকূল করেছে optim যদি আপনি 0 পান না, এবং আপনার অনুলিপি নির্মাণকারী হাস্যকরভাবে ব্যয়বহুল, তবে আপনার কার্যগুলি থেকে উদাহরণগুলি ফেরতের বিকল্প উপায়গুলি অনুসন্ধান করুন।


1

প্রথমত আপনার কোডটিতে একটি ত্রুটি রয়েছে, আপনার বোঝানো হয়েছে Thing *thing(new Thing());এবং কেবল return thing;

  • ব্যবহার shared_ptr<Thing>। এটি একটি পয়েন্টার হিসাবে এটি deref। যখন Thingঅন্তর্ভুক্তটির শেষ রেফারেন্স সুযোগের বাইরে চলে যায় তখন এটি আপনার জন্য মুছে ফেলা হবে ।
  • প্রথম সমাধানটি নিষ্পাপ গ্রন্থাগারগুলিতে খুব সাধারণ common এটির কিছু কর্মক্ষমতা এবং সিনট্যাক্টিকাল ওভারহেড রয়েছে, সম্ভব হলে এটি এড়িয়ে চলুন
  • দ্বিতীয় সমাধানটি কেবলমাত্র যদি আপনি গ্যারান্টি দিতে পারেন তবে কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হবে না, বা যখন পারফরম্যান্স একেবারে সমালোচিত হয় (আপনি এটি এমনকি প্রাসঙ্গিক হওয়ার আগেই সি বা অ্যাসেমব্লির সাথে হস্তক্ষেপ করবেন)।

0

আমি নিশ্চিত যে সি ++ বিশেষজ্ঞ আরও ভাল উত্তর নিয়ে আসবেন তবে ব্যক্তিগতভাবে আমি দ্বিতীয় পদ্ধতির পছন্দ করি। স্মার্ট পয়েন্টারগুলি ব্যবহার করে ভুলে যাওয়ার সমস্যা deleteএবং যেমনটি আপনি বলেছিলেন, হাতের আগে কোনও বস্তু তৈরি করার চেয়ে এটি আরও পরিষ্কার দেখাচ্ছে (এবং যদি আপনি এটি গাদাতে বরাদ্দ করতে চান তবে এটি মুছতে হবে) looks

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