কেন কোনও ফাংশন থেকে 'ভেক্টর' ফিরিয়ে দেওয়া ঠিক হবে?


108

এই কোড বিবেচনা করুন। আমি এই ধরণের কোডটি বেশ কয়েকবার দেখেছি। wordsস্থানীয় ভেক্টর is এটি কোনও ফাংশন থেকে ফেরত পাওয়া কীভাবে সম্ভব?

আমরা গ্যারান্টি দিতে পারি যে এটি মারা যাবে না?

 std::vector<std::string> read_file(const std::string& path)
 {
    std::ifstream file("E:\\names.txt");

    if (!file.is_open())
    {
        std::cerr << "Unable to open file" << "\n";
        std::exit(-1);
    }

    std::vector<string> words;//this vector will be returned
    std::string token;

    while (std::getline(file, token, ','))
    {
        words.push_back(token);
    }

    return words;
}

18
ফিরে আসার সময় এটি অনুলিপি করা হয়।
গীতিয়ানুয়াও

6
কেউ নিশ্চয়তা .. এটা হবে মারা যায়, কিন্তু পরে এটি কপি করা হচ্ছে।
মারউন

7
আপনার ক্রিয়াকলাপটি কোনও রেফারেন্স ফিরিয়ে দিলে আপনার কেবলমাত্র সমস্যা রয়েছে:std::vector<std::string>&
ক্যাডুচন

14
@ সিংগুয়ানিয়ো না, এটি সরানো হবে।
ডানফোল্ড

15
@ সংগুয়ানিয়াও হ্যাঁ সি ++ 11 হ'ল বর্তমান মান, সুতরাং সি ++ 11 হ'ল সি ++।
ডানফোল্ড

উত্তর:


68

আমরা গ্যারান্টি দিতে পারি যে এটি মারা যাবে না?

যতক্ষণ কোনও রেফারেন্স ফেরত পাওয়া যায় না, এটি করা একেবারে ঠিক। wordsফলাফল গ্রহণ করে ভেরিয়েবলে সরানো হবে।

স্থানীয় পরিবর্তনশীল সুযোগের বাইরে চলে যাবে। এটি সরানোর পরে (বা অনুলিপি করা)।


2
তবে কী দক্ষ বা কোনও পারফরম্যান্স উদ্বেগগুলি ভেক্টরটির জন্য বলছে যা 1000 এন্ট্রি রাখতে পারে?
জার

@ জাজনে এই প্রশ্ন ছিল? এছাড়াও আমি চলন্ত উল্লেখ করেছি যা প্রত্যাবর্তন মূল্যের একটি অনুলিপি গ্রহণ করা এড়াতে পারে (কমপক্ষে বর্তমান মানের সাথে উপলব্ধ)।
ῥεῖ

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

@ জাজান "আমি আশঙ্কা করছি তারা এটিকে এর সদৃশ হিসাবে চিহ্নিত করবে" ভাল হতে পারে। শুধু কটাক্ষপাত আছে উচ্চতর ভোট উত্তর । এমনকি পুরানো বাস্তবায়নের জন্যও আপনার চিন্তা করা উচিত নয়, এগুলি সাধারণত যাহাই হউক না কেন এই সংকলকগুলি দ্বারা সঠিকভাবে অনুকূলিত হবে।
ῥεῖ ῥεῖ

107

প্রাক সি ++ 11:

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

এই বিবরণ দেখুন এবং আরও তথ্যের জন্য উত্তর

সি ++ 11:

ফাংশনটি মান সরিয়ে দেবে। আরও তথ্যের জন্য এই উত্তর দেখুন ।


2
এটি সরানো হবে, অনুলিপি করা হবে না। এটি গ্যারান্টিযুক্ত
ডানফোল্ড

1
এটি কি C ++ 10 এর জন্যও প্রযোজ্য?
টিম মায়ার

28
সি ++ 10 এর মতো কোনও জিনিস নেই।
ডানফোল্ড

সি ++ 03 এর কোনও চলমান শব্দার্থবিজ্ঞান ছিল না (তবে অনুলিপিটি যদিও অন্যদিকে থাকতে পারে), তবে সি ++ সি ++ 11 এবং প্রশ্নটি সি ++ সম্পর্কে ছিল।
ডানফোল্ড

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

26

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

তবে এই ক্ষেত্রে এটি কাজ করে, কারণ এটি std::vectorএকটি শ্রেণি, এবং স্ট্রাক্টের মতো ক্লাসগুলি কলকারীদের প্রসঙ্গে কপি করা যেতে পারে (এবং হবে)। [প্রকৃতপক্ষে, বেশিরভাগ সংকলকরা "রিটার্ন মান অপ্টিমাইজেশন" নামক কিছু ব্যবহার করে এই বিশেষ ধরণের অনুলিপিটি অনুকূল করে তুলবে, বিশেষত বড় কোনও বস্তুগুলি যখন কোনও ফাংশন থেকে ফিরে আসে তখন এটি অনুলিপি করা থেকে বাঁচানোর জন্য প্রবর্তিত হয়, তবে এটি একটি অপ্টিমাইজেশন এবং প্রোগ্রামার দৃষ্টিকোণ থেকে এটি হবে এমন আচরণ করুন যেন অ্যাসাইনমেন্ট কনস্ট্রাক্টরকে বস্তুর জন্য ডাকা হয়েছিল]

যতক্ষণ আপনি ফাংশনটির মধ্যে থাকা কোনও কিছুর কোনও পয়েন্টার বা কোনও রেফারেন্স ফেরৎ না দিলে আপনি ভাল আছেন।


13

আচরণটি ভালভাবে বুঝতে, আপনি এই কোডটি চালাতে পারেন:

#include <iostream>

class MyClass
{
  public:
    MyClass() { std::cout << "run constructor MyClass::MyClass()" << std::endl; }
    ~MyClass() { std::cout << "run destructor MyClass::~MyClass()" << std::endl; }
    MyClass(const MyClass& x) { std::cout << "run copy constructor MyClass::MyClass(const MyClass&)" << std::endl; }
    MyClass& operator = (const MyClass& x) { std::cout << "run assignation MyClass::operator=(const MyClass&)" << std::endl; }
};

MyClass my_function()
{
  std::cout << "run my_function()" << std::endl;
  MyClass a;
  std::cout << "my_function is going to return a..." << std::endl;
  return a;
}

int main(int argc, char** argv)
{
  MyClass b = my_function();

  MyClass c;
  c = my_function();

  return 0;
}

আউটপুট নিম্নলিখিত:

run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run constructor MyClass::MyClass()
run my_function()
run constructor MyClass::MyClass()
my_function is going to return a...
run assignation MyClass::operator=(const MyClass&)
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()
run destructor MyClass::~MyClass()

নোট করুন যে এই উদাহরণটি C ++ 03 প্রসঙ্গে সরবরাহ করা হয়েছিল, এটি সি ++> = 11 এর জন্য উন্নত করা যেতে পারে


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

@ সোমেগুই আমি সম্মত, কিন্তু আমি সি ++ 11 ব্যবহার করি না। আমার যে জ্ঞান নেই তা সরবরাহ করতে পারি না। আমি একটি নোট যোগ করুন। সি ++> = 11. :
কাদুচোন

-5

আমি সম্মত নই এবং কোনও ফেরত দেওয়ার পরামর্শ দিচ্ছি না vector:

vector <double> vectorial(vector <double> a, vector <double> b)
{
    vector <double> c{ a[1] * b[2] - b[1] * a[2], -a[0] * b[2] + b[0] * a[2], a[0] * b[1] - b[0] * a[1] };
    return c;
}

এটি অনেক দ্রুত:

void vectorial(vector <double> a, vector <double> b, vector <double> &c)
{
    c[0] = a[1] * b[2] - b[1] * a[2]; c[1] = -a[0] * b[2] + b[0] * a[2]; c[2] = a[0] * b[1] - b[0] * a[1];
}

আমি ভিজ্যুয়াল স্টুডিও 2017 তে নিম্নলিখিত ফলাফলের সাথে প্রকাশের মোডে পরীক্ষা করেছি:

8.01 এমওপিগুলি রেফারেন্স দ্বারা
5.09 এমওপিগুলি ভেক্টর ফেরত

ডিবাগ মোডে, বিষয়গুলি আরও খারাপ:

0.053 MOPS রেফারেন্স সহ
0.034 এমওপিগুলি রিটার্ন ভেক্টর দ্বারা


-10

এটি আসলে ডিজাইনের ব্যর্থতা। অপেক্ষাকৃত তুচ্ছ নয় এমন কোনও কিছুর জন্য আপনি আদিম নয় এমন কোনও জিনিসের বিনিময়ের মান ব্যবহার করবেন না।

আদর্শ সমাধানটি রেফারেন্স / পয়েন্টার সংক্রান্ত সিদ্ধান্ত এবং একটি "কনস্ট const 'ওয়াই \' নেস" এর বর্ণনাকারী হিসাবে যথাযথ ব্যবহার সহ একটি রিটার্ন প্যারামিটারের মাধ্যমে প্রয়োগ করা উচিত।

এর শীর্ষে, আপনার বুঝতে হবে যে সি এবং সি ++ এর অ্যারেতে থাকা লেবেলটি কার্যকরভাবে একটি পয়েন্টার এবং এর সাবস্ক্রিপশনটি কার্যকরভাবে একটি অফসেট বা সংযোজন প্রতীক।

সুতরাং লেবেল বা পিটিআরটি অ্যারে_পিটার === অ্যারে লেবেল এইভাবে ফু [অফসেট] ফিরে আসবে সত্যিই মেমরি পয়েন্টার লোকেশনে ফিরুন উপাদান বলছে + টাইপ রিটার্ন টাইপের অফসেট।


5
..........কি. এটি স্পষ্ট বলে মনে হয় যে আপনি "ডিজাইনের ব্যর্থতা" এর মতো অভিযোগগুলি ছুঁড়ে দেওয়ার পক্ষে যোগ্য নন। এবং সত্য, RVO এবং পদক্ষেপ অপারেশন দ্বারা মান শব্দার্থবিদ্যা প্রচারের অন্যতম প্রধান সাফল্য আধুনিক সি ++ শৈলীর স্প্যানিশ ভাষায়। তবে আপনি কাঁচা অ্যারে এবং পয়েন্টারগুলি সম্পর্কে ভাবতে আটকে আছেন বলে মনে হচ্ছে, তাই আপনি এটি বুঝতে পেরেছি।
আন্ডারস্কোর_
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.