কখন ফাংশন-স্তরের স্থিতিশীল ভেরিয়েবলগুলি বরাদ্দ / প্রাথমিক করা হয়?


90

আমি পুরোপুরি আত্মবিশ্বাসী যে বিশ্বব্যাপী ঘোষিত ভেরিয়েবলগুলি প্রোগ্রাম শুরুর সময় বরাদ্দ (এবং প্রযোজ্য ক্ষেত্রে আঞ্চলিতকরণ) হয়ে যায়।

int globalgarbage;
unsigned int anumber = 42;

কিন্তু একটি ফাংশন মধ্যে সংজ্ঞায়িত স্থির বেশী সম্পর্কে কি?

void doSomething()
{
  static bool globalish = true;
  // ...
}

globalishবরাদ্দ করার জন্য স্থান কখন ? আমি অনুমান করছি প্রোগ্রামটি কখন শুরু হয়। তবে কি তাও আবার শুরু হয়ে যায়? বা doSomething()প্রথম বলা হয় যখন এটি আরম্ভ করা হয়?

উত্তর:


92

আমি এটি সম্পর্কে কৌতূহল ছিলাম তাই আমি নিম্নলিখিত পরীক্ষার প্রোগ্রামটি লিখেছি এবং এটি g ++ সংস্করণ 4.1.2 সহ সংকলিত করেছি।

include <iostream>
#include <string>

using namespace std;

class test
{
public:
        test(const char *name)
                : _name(name)
        {
                cout << _name << " created" << endl;
        }

        ~test()
        {
                cout << _name << " destroyed" << endl;
        }

        string _name;
};

test t("global variable");

void f()
{
        static test t("static variable");

        test t2("Local variable");

        cout << "Function executed" << endl;
}


int main()
{
        test t("local to main");

        cout << "Program start" << endl;

        f();

        cout << "Program end" << endl;
        return 0;
}

ফলাফলগুলি আমার প্রত্যাশা মতো ছিল না। স্থির অবজেক্টের জন্য কনস্ট্রাক্টরটিকে প্রথম বার ফাংশন না বলা পর্যন্ত ডাকা হত না। এখানে ফলাফল:

global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed

30
একটি স্পষ্টকরণ হিসাবে: স্ট্যাটিক ভেরিয়েবল প্রথমবার কার্যকর হয় যখন তার ফাংশনটি ডাকা হয় না তখন তার ঘোষণাকে হিট করে। ফাংশনের শুরুতে যদি আপনার কেবলমাত্র একটি স্ট্যাটিক থাকে (উদাহরণস্বরূপ আপনার উদাহরণে) এগুলি একই, তবে অগত্যা নয়: উদাহরণস্বরূপ যদি আপনার 'যদি (...) {স্থির মাই ক্লাস এক্স থাকে; ...} ', তারপরে যদি' স্টেটমেন্টের শর্তটি মিথ্যা হিসাবে মূল্যায়ন করে 'ক্ষেত্রে সেই ফাংশনটির প্রথম সম্পাদনের সময়' এক্স 'সমস্ত ক্ষেত্রে আরম্ভ করা হবে না।
উন্নত

4
তবে এটি রানটাইম ওভারহেডের দিকে পরিচালিত করে না, যেহেতু প্রতিবার স্ট্যাটিক ভেরিয়েবল ব্যবহার করা হয়, প্রোগ্রামটি এটি আগে ব্যবহার করা হয়েছে কিনা তা পরীক্ষা করে দেখতে হবে, যদি না হয় তবে এটি আরম্ভ করাতে হবে? সেক্ষেত্রে এই ধরণের কিছুটা কিছুটা চুষে যায়।
হ্যালো গুডবাই

নিখুঁত চিত্র
1gnWizard

@ ওভিও: হ্যাঁ, সূচনাটি থ্রেড-সেফ। : আরো বিস্তারিত জানার জন্য যে প্রশ্ন দেখুন stackoverflow.com/questions/23829389/...
Rémi

4
@ হেলো গুডবি: হ্যাঁ, এটি রানটাইম ওভারহেডের দিকে নিয়ে যায়। এছাড়াও যে প্রশ্ন দেখুন: stackoverflow.com/questions/23829389/...
Rémi

53

সি ++ স্ট্যান্ডার্ড থেকে কিছু প্রাসঙ্গিক শব্দভাণ্ডার:

৩.6.২ অ-স্থানীয় অবজেক্টের সূচনা [বেসিক.স্টার্ট.ইনটি]

স্ট্যাটিক স্টোরেজ সময়কাল (সঙ্গে অবজেক্টের জন্য স্টোরেজ basic.stc.static ) হইবে শূন্য সক্রিয়া ( dcl.init ) আগের অন্য কোন আরম্ভের সঞ্চালিত হয়। ধ্রুবক এক্সপ্রেশন ( expr.const ) দিয়ে স্ট্যাটিক স্টোরেজ সময়কাল সহ POD ধরণের ( বেসিক.প্রকারের ) অবজেক্টগুলি কোনও গতিশীল সূচনা হওয়ার আগেই আরম্ভ করা হবে। স্থিতিশীল স্টোরেজ সময়কালের সাথে একই স্থানের ইউনিটে সংজ্ঞায়িত এবং গতিশীলভাবে আরম্ভকৃত নামের স্পেসের অবজেক্টগুলি যে সংজ্ঞা অনুবাদ ইউনিটে প্রদর্শিত হবে সেই ক্রমে প্রাথমিকভাবে শুরু করা হবে। [দ্রষ্টব্য: dcl.init.aggr সামগ্রিক সদস্যদের আরম্ভ করার আদেশটি বর্ণনা করে। স্থানীয় স্ট্যাটিক অবজেক্টের সূচনাটি stmt.dcl তে বর্ণিত । ]

[নীচের আরও পাঠ্য সংকলক লেখকদের আরও স্বাধীনতা যোগ করে]

7.7 ঘোষণার বিবৃতি [stmt.dcl]

...

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

      int foo(int i)
      {
          static int s = foo(2*i);  // recursive call - undefined
          return i+1;
      }

- শেষ উদাহরণ ]

স্থির স্টোরেজ সময়কাল সহ একটি স্থানীয় অবজেক্টের জন্য ডেস্ট্রাক্টর কার্যকর করা হয় এবং কেবলমাত্র যদি ভেরিয়েবলটি নির্মিত হয়। [দ্রষ্টব্য: বেসিক.স্টার্ট.এমটারম স্থিতিশীল স্টোরেজ সময়কাল সহ স্থানীয় বস্তুগুলি যাতে বিনষ্ট হয় সেই ক্রমের বর্ণনা দেয়। ]


এটি আমার প্রশ্নের উত্তর দিয়েছে এবং স্বীকৃত উত্তরের মতো "উপাখ্যানক প্রমাণ" -র উপর নির্ভর করে না। আমি বিশেষত স্ট্যাটিকালি-ইনিশিয়ালড ফাংশন স্থানীয় স্ট্যাটিক অবজেক্টের কনস্ট্রাক্টারে ব্যতিক্রমগুলির এই উল্লেখটির সন্ধান If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration.
করছিলাম

26

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


4
একেবারেই নয়, স্থানীয় স্ট্যাটিকগুলি বরাদ্দ করা হয় এবং "প্রোগ্রাম লোড এ" শূন্য-ইনিশিয়েলাইজ করা হয় (উদ্ধৃতিগুলিতে, কারণ এটি ঠিক ঠিক নয়), এবং তারপরে যে ফাংশনটি তারা প্রবেশ করানো হয়েছিল প্রথম বার এটি পুনরায় পুনর্নির্মাণ করে।
হাঁস

দেখে মনে হচ্ছে link লিঙ্কটি এখন 7 বছর পরে ভেঙে গেছে।
স্টিভ

4
হ্যাঁ, লিঙ্কটি ভেঙে গেছে। এখানে একটি সংরক্ষণাগার রয়েছে: web.archive.org/web/20100328062506/http://www.acm.org/…
ইউজিন

10

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

@ অ্যাডাম: সংকলক দ্বারা কোডের ইনজেকশনগুলির নেপথ্যে এটিই আপনি যে ফলাফলটি দেখেছেন তার কারণ reason


5

আমি অ্যাডাম পিয়ার্সের কাছ থেকে আবার কোড পরীক্ষা করার চেষ্টা করেছি এবং আরও দুটি কেস যুক্ত করেছি: ক্লাসে স্ট্যাটিক ভেরিয়েবল এবং পিওডি টাইপ। আমার সংকলকটি উইন্ডোজ ওএসে (মিনিজিডাব্লু -32) জি ++ 4.8.1। ফলাফল ক্লাসে স্থির পরিবর্তনশীল হয় বৈশ্বিক ভেরিয়েবলের সাথে একই আচরণ করা হয়। এর কনস্ট্রাক্টরকে মূল ফাংশনে প্রবেশের আগে ডাকা হবে।

  • উপসংহার (জি ++, উইন্ডোজ পরিবেশের জন্য):

    1. ক্লাসে গ্লোবাল ভেরিয়েবল এবং স্ট্যাটিক সদস্য : মূল ফাংশন (1) প্রবেশের আগে কনস্ট্রাক্টরকে ডাকা হয় ।
    2. স্থানীয় স্ট্যাটিক ভেরিয়েবল : নির্বাহক কেবল তখনই ডাকা হয় যখন মৃত্যুদণ্ড কার্যকর হওয়ার প্রথম সময়ে তার ঘোষণায় পৌঁছায়।
    3. যদি স্থানীয় স্ট্যাটিক পরিবর্তনশীল POD ধরনের , তাহলে এটি আরো আগে সক্রিয়া করা হয় প্রবেশ প্রধান ফাংশন (1) । পিওডি টাইপের উদাহরণ: স্থিতিশীল সংখ্যা সংখ্যা = 10;

(1) : সঠিক অবস্থা হওয়া উচিত: "একই অনুবাদ ইউনিট থেকে কোনও ফাংশন বলা হওয়ার আগে"। তবে, সাধারণের জন্য যেমন নীচের উদাহরণ হিসাবে, তবে এটি মূল ফাংশন।

<iostream> অন্তর্ভুক্ত করুন

#include < string>

using namespace std;

class test
{
public:
   test(const char *name)
            : _name(name)
    {
            cout << _name << " created" << endl;
    }

    ~test()
    {
            cout << _name << " destroyed" << endl;
    }

    string _name;
    static test t; // static member
 };
test test::t("static in class");

test t("global variable");

void f()
{
    static  test t("static variable");
    static int num = 10 ; // POD type, init before enter main function

    test t2("Local variable");
    cout << "Function executed" << endl;
}

int main()
{
    test t("local to main");
    cout << "Program start" << endl;
    f();
    cout << "Program end" << endl;
    return 0;
 }

ফলাফল:

static in class created
global variable created
local to main created
Program start
static variable created
Local variable created
Function executed
Local variable destroyed
Program end
local to main destroyed
static variable destroyed
global variable destroyed
static in class destroyed

লিনাক্স এনভিতে কেউ পরীক্ষা করেছে?


4

অথবা যখন ডোজ কিছু () প্রথম বলা হয় তখন এটি আরম্ভ করা হয়?

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

int foo = init(); // bad if init() throws something

int main() {
  try {
    ...
  }
  catch(...){
    ...
  }
}

তুমি লিখতে পারো

int& foo() {
  static int myfoo = init();
  return myfoo;
}

এবং চেষ্টা / ক্যাচ ব্লকের ভিতরে এটি ব্যবহার করুন। প্রথম কলটিতে, চলকটি আরম্ভ করা হবে। তারপরে, প্রথম এবং পরবর্তী কলগুলিতে, এর মান (রেফারেন্স দ্বারা) ফিরে আসবে।


3

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

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

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

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

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


4
এই প্রশ্নটি ফাংশন-স্কোপড স্ট্যাটিক্স সম্পর্কে। কমপক্ষে যখন তারা অনিয়ন্ত্রিত কনস্ট্রাক্টর থাকে তারা ফাংশনে প্রথম প্রবেশের সময় তাদের সূচনা করা হয়। বা আরও নির্দিষ্টভাবে, যখন সেই লাইনটি পৌঁছে যায়।
অ্যাডাম মিটস

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

কোড সেগমেন্ট বনাম বনাম ডেটা বিভাগটি এখানে কীভাবে গুরুত্বপূর্ণ তা আমি দেখতে পাচ্ছি না। আমি মনে করি ওপি থেকে আমাদের স্পষ্টতা দরকার। তিনি বলেছেন "এবং প্রযোজ্য হলে প্রাথমিককরণ"।
অ্যাডাম মিটস

4
ভেরিয়েবলগুলি কখনই কোড সেগমেন্টের মধ্যে বরাদ্দ করা হয় না; এইভাবে তারা লেখার যোগ্য হবে না।
বোটিসমারিয়াস

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