সি ++ এর মধ্যে "ইন্ট অ্যান্ড ফু ()" এর অর্থ কী?


114

মূল্য এবং মূল্যগুলির উপর এই ব্যাখ্যাটি পড়ার সময় , কোডগুলির এই লাইনগুলি আমার কাছে আটকে গেল:

int& foo();
foo() = 42; // OK, foo() is an lvalue

আমি এটি g ++ এ চেষ্টা করেছি, তবে সংকলকটি "foo () এর অপরিবর্তিত রেফারেন্স" বলে। আমি যদি যোগ করি

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

এটি সূক্ষ্ম সংকলন করে, তবে এটি চালানো বিভাগকে ত্রুটি দেয় । শুধু লাইন

int& foo();

উভয়ই সংকলন করে এবং কোনও সমস্যা ছাড়াই চলে।

এই কোড মানে কি? আপনি কীভাবে কোনও ফাংশন কলে একটি মান নির্ধারণ করতে পারেন এবং এটি কেন কোনও মূল্য নয়?


25
আপনি কোনও ফাংশন কলের জন্য কোনও মূল্য বরাদ্দ করছেন না , আপনি যে রেফারেন্সটি দেখবেন তার জন্য একটি মান নির্ধারণ করছেন ।
ফ্রেডেরিক হামিদী

3
@ ফ্রিডরিক হামিদি প্রত্যাশিত রেফারেন্সটি উল্লেখ করছে এমন একটি বস্তু নির্ধারণ করছে
এমএম

3
হ্যাঁ এটি বস্তুর জন্য একটি উপনাম; রেফারেন্সটি অবজেক্ট নয়
এমএম

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

4
এর জন্য ইতিমধ্যে একটি জিসিসি বাগ রয়েছে
জোটিক

উত্তর:


168

ব্যাখ্যাটি ধরে নেওয়া হচ্ছে যে এখানে কিছু যুক্তিসঙ্গত বাস্তবায়ন রয়েছে fooযার জন্য একটি বৈধের জন্য মূল্যমানের রেফারেন্স প্রদান করে int

যেমন বাস্তবায়ন হতে পারে:

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

এখন, যেহেতু fooএকটি লভ্যালু রেফারেন্স প্রদান করে, আমরা এর মতো রিটার্ন মানকে কিছু বরাদ্দ করতে পারি:

foo() = 42;

এটি aমান সহ গ্লোবাল আপডেট করবে 42যা আমরা ভেরিয়েবলটি সরাসরি অ্যাক্সেস করে বা fooআবার কল করে পরীক্ষা করতে পারি :

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}

অপারেটর হিসাবে যুক্তিযুক্ত []? বা অন্য কোনও সদস্যের পদ্ধতি অ্যাক্সেস করবেন?
জান দর্নিয়াক

8
রেফারেন্স সম্পর্কে বিভ্রান্তি দেওয়া, নমুনাগুলি থেকে স্থির স্থানীয় ভেরিয়েবলগুলি সরিয়ে ফেলা সম্ভবত সেরা। সূচনাটি অহেতুক জটিলতা যুক্ত করে, যা শেখার ক্ষেত্রে অন্তরায়। শুধু এটি একটি বিশ্বব্যাপী করুন।
হাঁস

72

অন্যান্য সমস্ত উত্তর ফাংশনের অভ্যন্তরে একটি স্থির ঘোষণা করে। আমি মনে করি এটি আপনাকে বিভ্রান্ত করতে পারে, তাই এটি একবার দেখুন:

int& highest(int  & i, int  & j)
{
    if (i > j)
    {
        return i;
    }
    return j;
}

int main()
{
    int a{ 3};
    int b{ 4 };
    highest(a, b) = 11;
    return 0;
}

যেহেতু highest()একটি রেফারেন্স দেয়, আপনি এটিতে একটি মূল্য নির্ধারণ করতে পারেন। যখন এই রান হয়, তখন b11 এ পরিবর্তন করা হবে আপনি যদি আরম্ভকরণটি পরিবর্তন করেন তবে এটি aছিল 8 বলে, তখন aএটি 11 এ পরিবর্তিত হবে 11 এটি এমন কিছু কোড যা অন্য উদাহরণগুলির তুলনায় বাস্তবে কোনও উদ্দেশ্যকে পরিপূরক করতে পারে।


5
কোন int = 3 এর পরিবর্তে int {3} লেখার কোনও কারণ আছে? এই সিনট্যাক্সটি আমার কাছে উপযুক্ত বলে মনে হচ্ছে না।
আলেকসি পেট্রেনকো

6
@ আলেক্সপেট্রেনকো এটি সর্বজনীন সূচনা। আমি যে উদাহরণটি কাজে লাগিয়েছিলাম তা ব্যবহার করে যাচ্ছিলাম। এটি সম্পর্কে কোনও অনুচিত নয়
কেট গ্রেগরি

3
আমি জানি এটি কি। a = 3 কেবল এতটাই ক্লিনার অনুভব করে। ব্যক্তিগত পছন্দ)
আলেকসেই পেট্রেনকো

কোনও ফাংশনের অভ্যন্তরে স্থির ঘোষণা যেমন কিছু লোককে বিভ্রান্ত করতে পারে, তেমনি আমিও বিশ্বাস করি যে সর্বজনীন সূচনা ব্যবহারের সম্ভাবনা রয়েছে।
এরিক্কার্টিন

@ আলেকসেই পেট্রেনকো ইনটেনের ক্ষেত্রে a = 1.3 এটি সুস্পষ্টভাবে একটি = 1 তে রূপান্তর করে Where যেখানে ইন্টের একটি {1.3 error ত্রুটির ফলস্বরূপ: রূপান্তর সংকীর্ণ করে।
সাত্তিক

32
int& foo();

Foo নামে একটি ফাংশন ঘোষণা করে যা একটিতে একটি রেফারেন্স দেয় int। উদাহরণগুলি যা করতে ব্যর্থ তা হ'ল আপনাকে সেই ক্রিয়াটির একটি সংজ্ঞা দেওয়া যা আপনি সংকলন করতে পারেন। যদি আমরা ব্যবহার করি

int & foo()
{
    static int bar = 0;
    return bar;
}

এখন আমাদের একটি ফাংশন রয়েছে যা রেফারেন্স দেয় bar। যেহেতু বার staticএটি ফাংশনে কল করার পরে এটি লাইভ থাকবে তাই এটির কোনও রেফারেন্স ফিরিয়ে দেওয়া নিরাপদ। এখন যদি আমরা করি

foo() = 42;

যা ঘটে তা হল আমরা 42 টি নির্ধারণ করি barযেহেতু আমরা রেফারেন্সকে অর্পণ করি এবং রেফারেন্সটি কেবলমাত্র একটি উপনাম bar। আমরা আবার ফাংশন কল যদি

std::cout << foo();

এটি barউপরের যেটি সেট করেছি তাই এটি 42 মুদ্রণ করবে ।


15

int &foo();foo()রিটার্ন টাইপের সাথে ডাকা একটি ফাংশন ঘোষণা করে int&। আপনি যদি কোনও শরীর সরবরাহ না করে এই ফাংশনটি কল করেন তবে আপনি একটি সংজ্ঞায়িত রেফারেন্স ত্রুটি পেতে পারেন।

আপনার দ্বিতীয় প্রয়াসে আপনি একটি ফাংশন সরবরাহ করেছেন int foo()। এটি দ্বারা ঘোষিত ফাংশনে একটি ভিন্ন রিটার্ন টাইপ রয়েছে int& foo();। সুতরাং আপনার একইটির দুটি ঘোষণা আছে fooযা মেলে না, যা ওয়ান সংজ্ঞা বিধি লঙ্ঘন করে যা অপরিজ্ঞাত আচরণের কারণ হয় (ডায়াগনস্টিকের প্রয়োজন হয় না)।

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

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}

10

int& foo();একটি ফাংশন যা একটি রেফারেন্স ফিরিয়ে দেয় int। আপনার প্রদত্ত ফাংশনটি intরেফারেন্স ছাড়াই ফেরত দেয় ।

আপনি করতে পারেন

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}

7

int & foo();এর অর্থ হল foo()একটি ভেরিয়েবলের রেফারেন্স দেয়।

এই কোডটি বিবেচনা করুন:

#include <iostream>
int k = 0;

int &foo()
{
    return k;
}

int main(int argc,char **argv)
{
    k = 4;
    foo() = 5;
    std::cout << "k=" << k << "\n";
    return 0;
}

এই কোড মুদ্রণ:

$ ./a.out কে = 5

কারণ foo()গ্লোবাল ভেরিয়েবলের একটি রেফারেন্স প্রদান করে k

আপনার সংশোধিত কোডে, আপনি ফেরত মানটিকে একটি রেফারেন্সে কাস্ট করছেন, যা তখন অবৈধ।


5

সেই প্রসঙ্গে & এর অর্থ একটি রেফারেন্স - সুতরাং foo কোনও int এর পরিবর্তে কোনও int- এ রেফারেন্স দেয়।

আপনি এখনও পয়েন্টার নিয়ে কাজ করেছেন কিনা তা আমি নিশ্চিত নই, তবে এটি একটি অনুরূপ ধারণা, আপনি আসলে ফাংশনটির বাইরে মানটি ফিরিয়ে দিচ্ছেন না - পরিবর্তে আপনি মেমরিতে অবস্থানটি সন্ধানের জন্য প্রয়োজনীয় তথ্যটি পাস করছেন যেখানে int হয়।

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

যদি আপনি ভাবছেন - আপনি সেগফল্ট পাওয়ার কারণটি হ'ল আপনি একটি সংখ্যাসূচক '2' ফিরিয়ে দিচ্ছেন - সুতরাং আপনি যদি কোনও সংঘটিত সংজ্ঞাটি সংজ্ঞায়িত করতে চান এবং তারপরে এটির সংশোধন করার চেষ্টা করছেন তবে এটিই সঠিক ত্রুটি মান।

আপনি যদি পয়েন্টার এবং ডায়নামিক মেমোরি সম্পর্কে এখনও না শিখে থাকেন তবে আমি প্রথমে সুপারিশ করবো যেহেতু কয়েকটি ধারণা আছে যা আমি মনে করি যে আপনি একবারে সমস্ত কিছু না শিখলে বোঝা শক্ত।


4

লিঙ্কযুক্ত পৃষ্ঠায় উদাহরণ কোডটি কেবল একটি ডামি ফাংশন ঘোষণা। এটি সংকলন করে না, তবে আপনার যদি কিছু ফাংশন সংজ্ঞায়িত করা থাকে তবে এটি সাধারণত কাজ করবে। উদাহরণটির অর্থ "যদি আপনার এই স্বাক্ষরটির সাথে কোনও ফাংশন থাকে তবে আপনি এটির মতো এটি ব্যবহার করতে পারেন"।

আপনার উদাহরণে, fooস্বাক্ষরের উপর ভিত্তি করে স্পষ্টভাবে একটি মূল্যকে ফিরিয়ে দেওয়া হচ্ছে, তবে আপনি একটি মূল্যকে ফেরান যা একটি মূল্যকে রূপান্তরিত হয়। এটি পরিষ্কারভাবে ব্যর্থ হওয়ার জন্য দৃ is় সংকল্পবদ্ধ। আপনি করতে পারেন:

int& foo()
{
    static int x;
    return x;
}

এবং x এর মান পরিবর্তন করে সফল হবে:

foo() = 10;

3

আপনার (foo) ফাংশনটি একটি ফাংশন যা কোনও পূর্ণসংখ্যার রেফারেন্স দেয় returns

সুতরাং আসুন বলি যে মূলত foo 5 ফিরে এসেছে এবং পরে আপনার মূল ফাংশনে আপনি বলে থাকেন foo() = 10;, তারপরে foo মুদ্রণ করে এটি 5 এর পরিবর্তে 10 মুদ্রণ করবে।

আমি আশা করি যে এটি উপলব্ধি করে :)

আমি প্রোগ্রামিংয়েও নতুন। আপনার মতামত তৈরি করে এমন প্রশ্নগুলি দেখতে আকর্ষণীয়! :)

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