সি ++ প্রোগ্রামারদের কেন 'নতুন' এর ব্যবহার কম করা উচিত?


873

আমি স্ট্যাক ওভারফ্লো প্রশ্ন std :: স্ট্রিং সঙ্গে স্টেম ওভারফ্লো প্রশ্ন মেমরি ফাঁস নেভিগেশন হোঁচট খেয়েছি std :: তালিকা <std :: શબ્દ> , এবং একটি মন্তব্য এই বলে:

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

তিনি আসলে কী বোঝাতে চেয়েছেন তা আমি নিশ্চিত নই।

কেন প্রায়শই সম্ভব সি ++ এর মান দ্বারা অবজেক্ট তৈরি করা উচিত এবং এটি অভ্যন্তরীণভাবে কী পার্থক্য করে?
আমি কি উত্তরটির ভুল ব্যাখ্যা দিয়েছি?

উত্তর:


1037

দুটি বহুল ব্যবহৃত মেমরি বরাদ্দ কৌশল রয়েছে: স্বয়ংক্রিয় বরাদ্দ এবং গতিশীল বরাদ্দ। সাধারণত, প্রতিটিটির জন্য মেমরির সাথে সম্পর্কিত অঞ্চল রয়েছে: স্ট্যাক এবং হিপ।

গাদা

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

সি ++ এ এটিকে স্বয়ংক্রিয় স্টোরেজ বলা হয় কারণ স্টোরেজটি সুযোগের শেষে স্বয়ংক্রিয়ভাবে দাবি করা হয়। বর্তমান কোড ব্লকের (ব্যবহার করে সীমানা {}) কার্যকর হওয়ার সাথে সাথে block ব্লকের সমস্ত ভেরিয়েবলের জন্য মেমরি স্বয়ংক্রিয়ভাবে সংগ্রহ করা হয়। এটি সেই মুহুর্তে যেখানে ধ্বংসকারীদের সংস্থানগুলি সংশোধন করার জন্য অনুরোধ করা হয়েছিল।

গাদা

গাদা আরও নমনীয় মেমরি বরাদ্দ মোডের জন্য অনুমতি দেয়। বুককিপিং আরও জটিল এবং বরাদ্দ ধীর। কোনও অন্তর্নিহিত প্রকাশের বিন্দু না থাকায় আপনাকে অবশ্যই মেমোরিটি ম্যানুয়ালি প্রকাশ করতে হবে deleteবা delete[]( freeসি তে) ব্যবহার করতে হবে । যাইহোক, একটি নিখুঁত রিলিজ পয়েন্টের অনুপস্থিতি হ'ল নমনীয়তার মূল চাবিকাঠি।

গতিশীল বরাদ্দ ব্যবহারের কারণ

এমনকি যদি গাদাটি ব্যবহার করা ধীর হয় এবং সম্ভাব্যভাবে মেমরি ফাঁস বা মেমরি খণ্ডিত হতে থাকে তবে গতিশীল বরাদ্দের ক্ষেত্রে পুরোপুরি ভাল ব্যবহারের ঘটনা রয়েছে, কারণ এটি কম সীমাবদ্ধ।

গতিশীল বরাদ্দ ব্যবহারের দুটি মূল কারণ:

  • সংকলনের সময় আপনার কত স্মৃতি দরকার তা আপনি জানেন না। উদাহরণস্বরূপ, একটি টেক্সট ফাইলটি স্ট্রিংয়ে পড়ার সময়, আপনি সাধারণত ফাইলটির আকারের আকারটি জানেন না, সুতরাং আপনি প্রোগ্রামটি চালনা না করা পর্যন্ত কতটা মেমরি বরাদ্দ করতে হবে তা আপনি সিদ্ধান্ত নিতে পারবেন না।

  • আপনি মেমরি বরাদ্দ করতে চান যা বর্তমান ব্লকটি ছেড়ে যাওয়ার পরে অব্যাহত থাকবে। উদাহরণস্বরূপ, আপনি কোনও ফাংশন লিখতে চাইতে পারেন যা string readfile(string path)কোনও ফাইলের বিষয়বস্তু ফেরত দেয়। এই ক্ষেত্রে, যদি স্ট্যাক পুরো ফাইল সামগ্রীটি ধারণ করতে পারে তবে আপনি কোনও ফাংশন থেকে ফিরে এসে বরাদ্দ হওয়া মেমরির ব্লক রাখতে পারবেন না।

গতিশীল বরাদ্দ কেন প্রায়শই অপ্রয়োজনীয়

সি ++ তে একটি ঝরঝরে কনস্ট্রাক্ট রয়েছে যার নাম ডেস্ট্রাক্টর । এই প্রক্রিয়াটি আপনাকে পরিবর্তকের জীবনকাল সহ সম্পদের আজীবন সারিবদ্ধ করে সংস্থানগুলি পরিচালনা করতে দেয়। এই কৌশলটিকে আরআইআইআই বলা হয় এবং এটি সি ++ এর বিশিষ্ট পয়েন্ট। এটি উত্সগুলিকে "মোড়ানো" করে ps std::stringএকটি নিখুঁত উদাহরণ। এই স্নিপেট:

int main ( int argc, char* argv[] )
{
    std::string program(argv[0]);
}

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

বিশেষত, এটি বোঝায় যে এই স্নিপেটে:

int main ( int argc, char* argv[] )
{
    std::string * program = new std::string(argv[0]);  // Bad!
    delete program;
}

অপ্রয়োজনীয় গতিশীল মেমরি বরাদ্দ রয়েছে। প্রোগ্রামটির জন্য আরও টাইপিং (!) প্রয়োজন এবং মেমোরিটি হ্রাস করতে ভুলে যাওয়ার ঝুঁকিটি প্রবর্তন করে। এটি কোনও আপাত সুবিধার সাথে এটি করে।

আপনার যত দ্রুত সম্ভব স্বয়ংক্রিয় স্টোরেজ ব্যবহার করা উচিত

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

  • টাইপ করতে দ্রুত;
  • রান যখন দ্রুত;
  • স্মৃতি / রিসোর্স লিকের প্রবণতা কম।

বোনাস পয়েন্ট

রেফারেন্স করা প্রশ্নে অতিরিক্ত উদ্বেগ রয়েছে। বিশেষত, নিম্নলিখিত শ্রেণি:

class Line {
public:
    Line();
    ~Line();
    std::string* mString;
};

Line::Line() {
    mString = new std::string("foo_bar");
}

Line::~Line() {
    delete mString;
}

নিম্নলিখিতগুলির তুলনায় আসলে ব্যবহার করা অনেক বেশি ঝুঁকিপূর্ণ:

class Line {
public:
    Line();
    std::string mString;
};

Line::Line() {
    mString = "foo_bar";
    // note: there is a cleaner way to write this.
}

কারণটি হ'ল std::stringএকটি অনুলিপি নির্মাণকারীকে যথাযথভাবে সংজ্ঞা দেয়। নিম্নলিখিত প্রোগ্রাম বিবেচনা করুন:

int main ()
{
    Line l1;
    Line l2 = l1;
}

আসল সংস্করণ ব্যবহার করে, এই প্রোগ্রামটি সম্ভবত ক্রাশ হবে, কারণ এটি deleteএকই স্ট্রিংয়ে দু'বার ব্যবহার করে। পরিবর্তিত সংস্করণ ব্যবহার করে, প্রতিটি Lineউদাহরণ নিজস্ব স্ট্রিং উদাহরণগুলির নিজস্ব হবে , প্রতিটি নিজস্ব স্মৃতিযুক্ত এবং উভয়ই প্রোগ্রামের শেষে প্রকাশিত হবে।

অন্যান্য নোট

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

আপনি যদি Lineক্লাসটি বিল্ডিং ব্লক হিসাবে ব্যবহার করেন :

 class Table
 {
      Line borders[4];
 };

তারপর

 int main ()
 {
     Table table;
 }

চারটি std::stringদৃষ্টান্ত, চারটি Lineদৃষ্টান্ত, একটি Tableউদাহরণ এবং সমস্ত স্ট্রিংয়ের বিষয়বস্তু বরাদ্দ করে এবং সবকিছু স্বয়ংক্রিয়ভাবে মুক্ত হয়


55
শেষে RAII উল্লেখ করার জন্য +1, তবে ব্যতিক্রম এবং স্ট্রাক আনওয়াইন্ডিং সম্পর্কে কিছু হওয়া উচিত।
টুবু

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

15
স্ট্যাক বরাদ্দের জন্য নেতিবাচক দিকটি উল্লেখ করার জন্য একটি দুর্দান্ত পরিপূরক হতে হবে (কমপক্ষে সি ++ 1x অবধি) - আপনি সচেতন না হলে আপনাকে প্রায়শই অযৌক্তিকভাবে বিষয়গুলি অনুলিপি করতে হবে। যেমন একটি Monsterএকটি spits আউট Treasureকরার Worldযখন এটি ডাইস। এর Die()পদ্ধতিতে এটি বিশ্বের ধন যোগ করে। world->Add(new Treasure(/*...*/))এটি মারা যাওয়ার পরে ধনটি সংরক্ষণের জন্য এটি অন্য ব্যবহার করতে হবে। বিকল্পগুলি shared_ptrহ'ল (ওভারকিল হতে পারে), auto_ptr(মালিকানা হস্তান্তরের জন্য দরিদ্র শব্দার্থক), মান দ্বারা পাস (অপব্যয়) এবং move+ unique_ptr(এখনও ব্যাপকভাবে প্রয়োগ করা হয়নি)।
kizzx2

7
আপনি স্ট্যাক-বরাদ্দ স্থানীয় ভেরিয়েবল সম্পর্কে যা বলেছিলেন তা কিছুটা বিভ্রান্তিকর হতে পারে। "স্ট্যাক" বলতে কল স্ট্যাককে বোঝায়, যা স্ট্যাক ফ্রেমগুলি সঞ্চয় করে । এটি এই স্ট্যাক ফ্রেমগুলি যা LIFO ফ্যাশনে সংরক্ষণ করা হয়। নির্দিষ্ট ফ্রেমের জন্য স্থানীয় ভেরিয়েবলগুলি বরাদ্দ করা হয় যেন তারা কোনও কাঠামোর সদস্য হয়।
সোমবার

7
@ সোমেগুয়ে: আসলে, ব্যাখ্যাটি সঠিক নয়। বাস্তবায়নটির বরাদ্দ নীতিতে স্বাধীনতা রয়েছে। যাইহোক, ভেরিয়েবলগুলি একটি LIFO ফ্যাশনে আরম্ভ এবং ধ্বংস করা প্রয়োজন, সুতরাং সাদৃশ্যটি ধারণ করে। আমি মনে করি না যে এটির উত্তরটি আরও জটিল করে তোলার কাজ।
আন্দ্রে কারন

171

কারণ স্ট্যাকটি দ্রুত এবং লিক-প্রুফ

সি ++ তে, কোনও নির্দিষ্ট ফাংশনে প্রতিটি স্থানীয় স্কোপ অবজেক্টের জন্য - স্ট্যাকের উপরে - স্থান বরাদ্দ করার একক নির্দেশনা লাগে এবং সেই মেমরিটির কোনও ফাঁকা হওয়া অসম্ভব। "মন্তব্যটি স্ট্যাকটি ব্যবহার করুন এবং গাদা নয়" এর মতো কিছু বলার জন্য সেই মন্তব্যে অভিযুক্ত (বা উদ্দেশ্য হওয়া উচিত)


18
"জায়গা বরাদ্দের জন্য এটি কেবলমাত্র একমাত্র নির্দেশনা" - ওহ, আজেবাজে কথা। নিশ্চিত যে এটি স্ট্যাক পয়েন্টার যুক্ত করতে শুধুমাত্র একটি নির্দেশ নেয়, কিন্তু শ্রেণীর যদি কোনও আকর্ষণীয় অভ্যন্তরীণ কাঠামো থাকে তবে স্ট্যাক পয়েন্টারটিতে যোগ করার চেয়ে আরও অনেক কিছু থাকবে। এটি জাভাতে স্থান বরাদ্দের জন্য কোনও নির্দেশনা নেয় না বলে সমানভাবে বৈধতা রয়েছে, কারণ সংকলক সংকলন সময়ে রেফারেন্সগুলি পরিচালনা করবে।
চার্লি মার্টিন

31
@ চার্লি সঠিক is স্বয়ংক্রিয় ভেরিয়েবলগুলি দ্রুত এবং বুদ্ধিমানের আরও সঠিক হবে।
অলিভার চার্লসওয়ার্থ

28
@ চার্লি: ক্লাস ইন্টার্নালগুলি যে কোনও উপায়ে স্থাপন করা দরকার। তুলনামূলকভাবে প্রয়োজনীয় জায়গা বরাদ্দ দেওয়ার বিষয়ে করা হচ্ছে।
অলিভার চার্লসওয়ার্থ

51
কাশি int x; return &x;
পিটারচেন

16
দ্রুত হ্যাঁ তবে অবশ্যই বোকা না। কিছুই বোকা না। আপনি স্ট্যাকওভারফ্লো পেতে পারেন :)
rxantos

107

কারণ জটিল।

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

std::string *someString = new std::string(...);
//Do stuff
delete someString;

এটি সহজ। তবে "ডু স্টাফ" ব্যতিক্রম ছুঁড়ে ফেললে কী ঘটে? উফফ: স্মৃতি ফুটো "কর স্টাফ" যদি returnতাড়াতাড়ি সমস্যা হয় তবে কি হবে ? উফফ: স্মৃতি ফুটো

এবং এই জন্য সহজতম ক্ষেত্রে । যদি আপনি সেই স্ট্রিংটি কারও কাছে ফেরত দেন তবে এখন তাদের এটি মুছতে হবে। এবং যদি তারা এটি আর্গুমেন্ট হিসাবে পাস করে তবে এটি প্রাপ্ত ব্যক্তির কি এটি মুছতে হবে? তাদের কখন এটি মুছে ফেলা উচিত?

বা, আপনি কেবল এটি করতে পারেন:

std::string someString(...);
//Do stuff

না delete । অবজেক্টটি "স্ট্যাক" তৈরি করা হয়েছিল এবং এটি সুযোগের বাইরে চলে গেলে এটি ধ্বংস হয়ে যায়। এমনকি আপনি অবজেক্টটিও ফিরিয়ে আনতে পারেন, সুতরাং এর বিষয়বস্তুগুলি কলিং ফাংশনে স্থানান্তর করে। আপনি অবজেক্টটি ফাংশনে পাস করতে পারেন (সাধারণত একটি রেফারেন্স বা কনস্ট-রেফারেন্স হিসাবে: void SomeFunc(std::string &iCanModifyThis, const std::string &iCantModifyThis)এবং আরও) forth

সব ছাড়া newএবং delete। মেমোরিটির মালিক কে বা এটি মোছার জন্য কে দায়ী তা নিয়ে কোনও প্রশ্ন নেই। যদি তুমি করো:

std::string someString(...);
std::string otherString;
otherString = someString;

এটি বোঝা যায় যে otherStringএর ডেটার একটি অনুলিপি রয়েছে someString। এটি কোনও পয়েন্টার নয়; এটি একটি পৃথক বস্তু। তাদের একই বিষয়বস্তু থাকতে পারে তবে আপনি অন্যটিকে প্রভাবিত না করে একটি পরিবর্তন করতে পারেন:

someString += "More text.";
if(otherString == someString) { /*Will never get here */ }

ধারণাটি দেখুন?


1
এই নোটটিতে ... যদি কোনও বস্তু গতিশীলভাবে বরাদ্দ করা হয় main(), প্রোগ্রামের সময়কালের জন্য উপস্থিত থাকে, পরিস্থিতির কারণে স্ট্যাকের উপরে সহজেই তৈরি করা যায় না এবং এটির জন্য পয়েন্টারগুলি কোনও ক্রিয়াকলাপে প্রেরণ করা হয় যার অ্যাক্সেসের প্রয়োজন হয় , কোনও প্রোগ্রাম ক্রাশের ক্ষেত্রে এটি কি ফুটো হতে পারে, বা এটি নিরাপদ হবে? আমি উত্তরটি ধরে নেব, যেহেতু ওএস প্রোগ্রামটির সমস্ত মেমোরিটি deallocating যুক্তিসঙ্গতভাবে এটিকে হ্রাস করতে হবে, তবে আমি কখনই এটি গ্রহণ করতে চাই না new
জাস্টিন সময় - মনিকা পুনরায়

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

75

তৈরি করা অবজেক্টগুলি newঅবশ্যই শেষ পর্যন্ত deleteসেগুলি ফাঁস হবে। ধ্বংসকারীকে ডাকা হবে না, স্মৃতি মুক্ত হবে না, পুরোপুরি bit যেহেতু সি ++ এর কোনও আবর্জনা সংগ্রহ নেই, তাই এটি একটি সমস্যা।

মান দ্বারা তৈরি করা বস্তুগুলি (যেমন স্ট্যাকের উপরে) যখন তারা সুযোগের বাইরে চলে যায় তখন স্বয়ংক্রিয়ভাবে মারা যায়। সংকলক দ্বারা ডেস্ট্রাক্টর কল callোকানো হয়, এবং ফাংশন রিটার্নের পরে মেমরিটি স্বয়ংক্রিয়ভাবে মুক্ত হয়।

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

এছাড়াও, প্রচুর পরিমাণে বহুবিবাহিত পরিস্থিতিতে newথ্রেডগুলির মধ্যে একটি বিতর্ক; অতিরিক্ত ব্যবহারের জন্য একটি পারফরম্যান্স প্রভাব থাকতে পারে new। স্ট্যাক অবজেক্ট তৈরি হ'ল সংজ্ঞা থ্রেড-লোকাল, কারণ প্রতিটি থ্রেডের নিজস্ব স্ট্যাক থাকে has

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


9
+1 টি। "" তৈরি করা বিষয়গুলি newঅবশ্যই অবশেষে deleteসেগুলি ফাঁস হবে। " - আরও খারাপ, new[]অবশ্যই এটির সাথে মিলে যেতে হবে delete[]এবং আপনি যদি অপ্রকাশিত আচরণ পান তবে আপনি delete new[]মেমরি বা delete[] new-ed মেমরিযুক্ত হয়ে থাকেন - খুব কম সংকলকই এ সম্পর্কে সতর্ক করে দেয় (সিপচেকের মতো কিছু সরঞ্জাম তারা যখন পারে তখন করতে পারে)।
টনি ডেলরয়

3
@ টনিডেলরোয় এমন পরিস্থিতি রয়েছে যেখানে সংকলক এটি সতর্ক করতে পারে না। কোনও ফাংশন যদি কোনও পয়েন্টার দেয়, তবে এটি নতুন (একক উপাদান) বা নতুন [] হলে তৈরি করা যেতে পারে।
fbafelip

32
  • সি ++ নিজের দ্বারা কোনও মেমরি পরিচালককে নিয়োগ দেয় না। অন্যান্য ভাষার মতো সি #, জাভাতে মেমরিটি পরিচালনা করতে আবর্জনা সংগ্রহকারী রয়েছে
  • সি ++ প্রয়োগগুলি মেমরির বরাদ্দ করতে সাধারণত অপারেটিং সিস্টেমের রুটিন ব্যবহার করে এবং খুব বেশি নতুন / মুছলে উপলভ্য মেমরিটিকে খণ্ডিত করতে পারে
  • যে কোনও অ্যাপ্লিকেশন সহ, যদি মেমরিটি ঘন ঘন ব্যবহার করা হয় তবে এটির প্রাক-বরাদ্দ করা এবং যখন প্রয়োজন হয় না তখন ছেড়ে দেওয়ার পরামর্শ দেওয়া হয়।
  • ভুল মেমরি পরিচালনা মেমরি ফাঁস হতে পারে এবং এটি ট্র্যাক করা সত্যিই কঠিন। সুতরাং ফাংশনের সুযোগের মধ্যে স্ট্যাক অবজেক্টগুলি ব্যবহার করা একটি প্রমাণিত কৌশল
  • স্ট্যাক অবজেক্টগুলি ব্যবহার করার ক্ষয়ক্ষতিটি হ'ল, এটি ফেরত দেওয়ার সময়, ফাংশনগুলিতে পাস করার ক্ষেত্রে একাধিক অনুলিপি তৈরি করে However তবে স্মার্ট সংকলকগুলি এই পরিস্থিতি সম্পর্কে ভাল জানেন এবং তারা পারফরম্যান্সের জন্য ভালভাবে অনুকূলিত হয়েছেন
  • মেমরিটি দুটি পৃথক স্থানে বরাদ্দ করা এবং প্রকাশ করা হলে এটি সি ++ তে সত্যই ক্লান্তিকর। মুক্তির দায়িত্ব সর্বদা একটি প্রশ্ন এবং বেশিরভাগ ক্ষেত্রে আমরা কিছু সাধারণ অ্যাক্সেসযোগ্য পয়েন্টার, স্ট্যাক অবজেক্টস (সর্বাধিক সম্ভব) এবং অটো_পিটারের মতো কৌশলগুলি (আরআইআইআই অবজেক্টস) এর উপর নির্ভর করি mostly
  • সবচেয়ে ভাল কথাটি হ'ল, আপনি মেমরির উপর নিয়ন্ত্রণ রেখেছেন এবং সবচেয়ে খারাপটি হ'ল আমরা যদি অ্যাপ্লিকেশনটির জন্য একটি ভুল মেমরি পরিচালনা নিযুক্ত করি তবে মেমরির উপর আপনার কোনও নিয়ন্ত্রণ থাকবে না। মেমরির বিপর্যয়ের কারণে ক্র্যাশগুলি হ'ল সর্বাধিকতম এবং খুঁজে পাওয়া শক্ত।

5
আসলে, মেমরি বরাদ্দকারী যে কোনও ভাষার মেমরি ম্যানেজার থাকে, সি সহ। বেশিরভাগগুলি কেবল খুব সাধারণ, যেমন ইনট * x = ম্যালোক (4); int * y = malloc (4); ... প্রথম কল মেমরি বরাদ্দ করবে, ওরফে মেমরির জন্য ওএস জিজ্ঞাসা করবে, (সাধারণত খণ্ডগুলি 1k / 4k এ) যাতে দ্বিতীয় কলটি আসলে মেমরি বরাদ্দ না করে, তবে শেষ বরাদ্দটির জন্য এই অংশটি বরাদ্দ করে। আইএমও, আবর্জনা সংগ্রহকারীরা মেমরি পরিচালক নয়, কারণ এটি কেবল মেমরির স্বয়ংক্রিয়ভাবে ক্ষয়িষ্ণুতা পরিচালনা করে। মেমোরি ম্যানেজার বলা যায়, এটি কেবল ক্ষয়িষ্ণু নয় মেমরির বন্টনও পরিচালনা করে handle
রাহলি

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

সি ++ "অপারেটিং সিস্টেমের রুটিনগুলি ব্যবহার করে না"; এটি ভাষার অংশ নয়, এটি কেবল একটি সাধারণ বাস্তবায়ন। সি ++ এমনকি কোনও অপারেটিং সিস্টেম ছাড়াই চলতে পারে।
einpoklum

22

আমি দেখতে পাচ্ছি যে নতুন হিসাবে যতটা সম্ভব সম্ভব করার কয়েকটি গুরুত্বপূর্ণ কারণ মিস হয়েছে:

অপারেটরের newএকটি অ-নিষ্ক্রিয় নির্বাহের সময় রয়েছে

কল newকরার ফলে আপনার প্রক্রিয়ায় ওএসকে একটি নতুন শারীরিক পৃষ্ঠা বরাদ্দ করতে পারে এবং নাও পারে এটি আপনি যদি প্রায়শই করেন তবে এটি বেশ ধীর হতে পারে। বা এটি ইতিমধ্যে একটি উপযুক্ত মেমরি অবস্থান প্রস্তুত থাকতে পারে, আমরা জানি না। যদি আপনার প্রোগ্রামটির সামঞ্জস্যপূর্ণ এবং পূর্বাভাসযোগ্য সম্পাদনের সময় থাকতে হয় (যেমন একটি রিয়েল-টাইম সিস্টেম বা গেম / পদার্থবিজ্ঞানের সিমুলেশনের মতো) newআপনার সময় সমালোচনামূলক লুপগুলি এড়াতে হবে ।

অপারেটর newএকটি অন্তর্নিহিত থ্রেড সিঙ্ক্রোনাইজেশন

হ্যাঁ আপনি আমাকে শুনেছেন, আপনার পৃষ্ঠার টেবিলগুলি সামঞ্জস্যপূর্ণ তা নিশ্চিত করার জন্য আপনার ওএসের প্রয়োজন এবং যেমন কলিংয়ের newফলে আপনার থ্রেডটি একটি অন্তর্নির্মিত মিউটেক্স লক অর্জন করবে। যদি আপনি ধারাবাহিকভাবে newঅনেকগুলি থ্রেড থেকে কল করে থাকেন তবে আপনি আসলে আপনার থ্রেডগুলি সিরিয়াল করছেন (আমি 32 সিপিইউ দিয়ে এটি করেছি, প্রতিটি newকয়েকশ বাইট পেতে প্রতিটি হিট করছে , ওচ! এটি ডিবাগ করার জন্য রয়েল পিটা ছিল)

বাকী যেমন ধীর, ভাঙন, ত্রুটিযুক্ত প্রবণ ইত্যাদি ইতিমধ্যে অন্যান্য উত্তর দ্বারা উল্লিখিত হয়েছে।


2
উভয়ই প্লেসমেন্ট নতুন / ডিলিট ব্যবহার করে এবং হাতের আগে মেমরি বরাদ্দ করে এড়ানো যায়। অথবা আপনি নিজেই স্মৃতি বরাদ্দ / মুক্ত করতে পারেন এবং তারপরে কনস্ট্রাক্টর / ডেস্ট্রাক্টরকে কল করতে পারেন। এইভাবে স্ট্যান্ড :: ভেক্টর সাধারণত কাজ করে।
rxantos

1
@ আরক্সান্টোস দয়া করে ওপি পড়ুন, এই প্রশ্নটি অপ্রয়োজনীয় মেমরির বরাদ্দ এড়ানো সম্পর্কে। এছাড়াও, কোনও স্থাপনার মোছা নেই।
এমিলি এল।

@ এমিলি এটিই ওপি বলতে বোঝায়, আমি মনে করি:void * someAddress = ...; delete (T*)someAddress
xryl669

1
স্ট্যাক ব্যবহার কার্যকরভাবে নির্ধারণের সময়গুলিতে নির্ধারিত নয়। যতক্ষণ না আপনি কল করেছেন mlock()বা অনুরূপ কিছু। এটি কারণ মেমরিটিতে সিস্টেমটি কম চলছে এবং স্ট্যাকের জন্য কোনও প্রস্তুত শারীরিক মেমরি পৃষ্ঠাগুলি উপস্থিত নেই সুতরাং ওএসের কার্যকর হওয়া এগিয়ে যাওয়ার আগে ডিস্কে কিছু ক্যাশে (পরিষ্কার নোংরা মেমরি) লেখার প্রয়োজন হতে পারে।
মিক্কো রেন্টালাইনেন

1
@ মিক্কোরান্টালাইনেন এটি প্রযুক্তিগতভাবে সত্য তবে কম স্মৃতি পরিস্থিতিতে আপনি যেভাবে কিছু করতে পারছেন না এমন কোনও ঝুঁকির কারণেই ডিস্কের দিকে এগিয়ে যাওয়ার কারণে সমস্ত ঝুঁকি রয়েছে performance যখন এটি করা যুক্তিসঙ্গত হয় তখন এটি নতুন কলগুলি এড়াতে পরামর্শটিকে কোনওভাবেই অকার্যকর করে না।
এমিলি এল।

21

প্রি-সি ++ 17:

কারণ আপনি যদি কোনও ফলকে কোনও স্মার্ট পয়েন্টারে আবদ্ধ করেন তবে এটি সূক্ষ্ম ফাঁসের ঝুঁকিতে পড়ে ।

একজন "সাবধানী" ব্যবহারকারী বিবেচনা করুন যিনি স্মার্ট পয়েন্টারে অবজেক্টগুলিকে মোড়ানো মনে রাখে:

foo(shared_ptr<T1>(new T1()), shared_ptr<T2>(new T2()));

এই কোডটি বিপজ্জনক কারণ এখানে গ্যারান্টি নেই যে হয় shared_ptrহয় হয় হয় আগে নির্মিত হয় T1বা হয় T2। সুতরাং, যদি অন্যটির মধ্যে একটি সফল হয় new T1()বা new T2()ব্যর্থ হয়, তবে প্রথম অবজেক্টটি ফাঁস হয়ে যাবে কারণ shared_ptrএটি ধ্বংস এবং হ্রাস করার কোনও অস্তিত্ব নেই।

সমাধান: ব্যবহার make_shared

পোস্ট-সি ++ 17:

এটি এখন আর কোনও সমস্যা নয়: সি ++ 17 এই অপারেশনগুলির ক্রমের উপর একটি বাধা আরোপ করে, এক্ষেত্রে নিশ্চিত করে যে প্রতিটি কলটি new()তত্ক্ষণাত সংশ্লিষ্ট স্মার্ট পয়েন্টার নির্মাণের পরে অনুসরণ করা উচিত, এর মধ্যে অন্য কোনও অপারেশন না করে। এটি বোঝায় যে, দ্বিতীয় new()বলা হওয়ার সময় , এটি গ্যারান্টিযুক্ত যে প্রথম অবজেক্টটি ইতিমধ্যে তার স্মার্ট পয়েন্টারে আবৃত হয়েছে, সুতরাং কোনও ব্যতিক্রম ছোঁড়ার ক্ষেত্রে কোনও ফাঁস আটকাবে।

সি ++ 17 দ্বারা প্রবর্তিত নতুন মূল্যায়ন আদেশের আরও বিশদ ব্যাখ্যা ব্যারি আরও একটি উত্তরে সরবরাহ করেছিলেন

সি ++ ১be এর অধীনে এটি এখনও একটি সমস্যা বলে চিহ্নিত করার জন্য @ রেমি লেউউকে ধন্যবাদ জানানো হয়েছে (যদিও এর চেয়ে কম) shared_ptrএটির জন্য : কনস্ট্রাক্টর তার নিয়ন্ত্রণ ব্লক বরাদ্দ করতে এবং নিক্ষেপ করতে ব্যর্থ হতে পারে, সেক্ষেত্রে এতে পাঠানো পয়েন্টারটি মোছা হয়নি।

সমাধান: ব্যবহার make_shared


5
অন্যান্য সমাধান: গতিশীলভাবে কখনই প্রতি লাইনে একাধিক বস্তুর বরাদ্দ করবেন না।
এন্টিমোনি

3
@ অ্যান্টিমনি: হ্যাঁ, আপনি যদি ইতিমধ্যে কোনও বরাদ্দ না দিয়েছিলেন তার তুলনায় আপনি যখন ইতিমধ্যে একটি বরাদ্দ করেছেন তখন একাধিক অবজেক্ট বরাদ্দ করা অনেক বেশি লোভনীয়।
ব্যবহারকারী541686

1
আমি মনে করি এর থেকে আরও ভাল উত্তর হ'ল যদি কোনও ব্যতিক্রম ডাকা হয় এবং কিছুই তা ধরা না দেয় তবে স্মার্ট_পিটার ফাঁস হবে।
নাটালি অ্যাডামস

2
এমনকি সি +++ পরবর্তী পোস্টে newসফল হওয়া এবং তারপরে পরবর্তী shared_ptrনির্মাণ ব্যর্থ হলে একটি ফাঁস এখনও ঘটতে পারে । std::make_shared()এটিও সমাধান করবে
রেমি লিবিউ

1
@ মেহরদাদ shared_ptrপ্রশ্নের মধ্যে থাকা কন্ট্রোল ব্লকের জন্য মেমরি বরাদ্দ করে যা ভাগ করে নেওয়া পয়েন্টার এবং মুছক সংরক্ষণ করে, তাই হ্যাঁ, এটি তাত্ত্বিকভাবে একটি মেমরি ত্রুটি ফেলে দিতে পারে। কেবল অনুলিপি, সরানো এবং এলিয়াসিং কনস্ট্রাক্টরগুলি নিক্ষেপযোগ্য। make_sharedকন্ট্রোল ব্লকের ভিতরে ভাগ করা অবজেক্টটি নিজেই বরাদ্দ করে, তাই ২ এর পরিবর্তে কেবলমাত্র 1 টি বরাদ্দ রয়েছে
রেমি লিবিউ

17

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

এটি করার সহজতম উপায় হ'ল স্বয়ংক্রিয় স্টোরেজটিতে অবজেক্টটি তৈরি করা, সুতরাং C ++ যখন সুযোগের বাইরে চলে যায় তখন এটি ধ্বংস করতে জানে:

 {
    File foo = File("foo.dat");

    // do things

 }

এখন, লক্ষ্য করুন যে আপনি যখন শেষ-বন্ধনী পরে block ব্লকটি পড়ে যান তখন fooসুযোগের বাইরে। সি ++ আপনার ডটারটিকে স্বয়ংক্রিয়ভাবে কল করবে। জাভা থেকে ভিন্ন, আপনার এটি জিসির সন্ধানের জন্য অপেক্ষা করতে হবে না।

আপনি লিখেছেন

 {
     File * foo = new File("foo.dat");

আপনি এটির সাথে সুস্পষ্টরূপে মেলে দেখতে চান

     delete foo;
  }

বা আরও ভাল, আপনার File *"স্মার্ট পয়েন্টার" হিসাবে বরাদ্দ করুন । আপনি যদি যত্নশীল না হন তবে এটি ফাঁস হতে পারে।

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

  class File {
    private:
      FileImpl * fd;
    public:
      File(String fn){ fd = new FileImpl(fn);}

তারপর FileImplহবে এখনও স্ট্যাক বরাদ্দ করা আবশ্যক।

এবং হ্যাঁ, আপনি অবশ্যই নিশ্চিত হন

     ~File(){ delete fd ; }

ক্লাসেও; এটি ছাড়াই, আপনি গাদা থেকে মেমরি ফাঁস করবেন এমনকি যদি আপনি স্পষ্টতই গাদাতে বরাদ্দ না করেন তবেও।


4
আপনার রেফারেন্সযুক্ত প্রশ্নের কোডটি একবার দেখে নেওয়া উচিত। এই কোডটিতে অবশ্যই অনেক কিছু ভুল হয়ে আছে।
আন্দ্রে কারন

7
আমি সম্মত হয়েছি যে new প্রতি সে ব্যবহারে কোনও ভুল নেই , তবে আপনি যদি মূল কোডটি দেখে থাকেন তবে মন্তব্যটির উল্লেখ ছিল, আপত্তিজনক আচরণ করা newহচ্ছে। কোডটি জাভা বা সি # এর মতো লেখা হয়েছিল, যেখানে newব্যবহারিকভাবে প্রতিটি চলক ব্যবহার করা হয়, যখন জিনিসগুলি স্ট্যাকের মধ্যে থাকতে আরও বোঝা যায়।
লুকে

5
ন্যায্য বিন্দু. তবে সাধারণ ক্ষতিগুলি এড়াতে সাধারণত নিয়ম প্রয়োগ করা হয়। এটি কোনও ব্যক্তির দুর্বলতা হোক বা না থাকুক, মেমরির ব্যবস্থাপনার মতো সাধারণ নিয়মের পরোয়ানা করার পক্ষে যথেষ্ট জটিল! :)
রববেন_ফোর্ড_ ফ্যান_বয়

9
@ চার্লি: মন্তব্যটি আপনাকে কখনও ব্যবহার করা উচিত নয় বলে মন্তব্য করে new। এরা বলছে যে আপনি যদি আছে গতিশীল বরাদ্দ এবং স্বয়ংক্রিয় স্টোরেজ মধ্যে পছন্দ, স্বয়ংক্রিয় সঞ্চয়স্থান ব্যবহার করে।
আন্দ্রে কারন

8
@ চর্লি: ব্যবহারে কোনও ভুল নেই new, তবে আপনি যদি ব্যবহার করেন তবে আপনি deleteএটি ভুল করছেন!
ম্যাথিউ এম।

16

new()যতটা সম্ভব কম ব্যবহার করা উচিত নয় । এটি যথাসম্ভব সাবধানতার সাথে ব্যবহার করা উচিত । এবং এটি ব্যবহারিকতত্ত্ব দ্বারা নির্ধারিত হিসাবে যতবার প্রয়োজন হিসাবে ব্যবহার করা উচিত।

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

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


9
"যদি আপনার অবজেক্টের জীবদ্দশার বর্তমান ক্ষেত্রের বাইরে যেতে হয় তবে নতুন () হ'ল সঠিক উত্তর" ... কেন অগ্রাধিকার হিসাবে মান দ্বারা ফিরে আসবেন না বা constরেফারেন্স বা পয়েন্টার দ্বারা কলার-স্কোপড ভেরিয়েবলকে কেন গ্রহণ করবেন না ...?
টনি ডেলরয়

2
@ টনি: হ্যাঁ, হ্যাঁ! কেউ রেফারেন্সের পক্ষে কথা শুনে খুশি হয়েছি। এই সমস্যা রোধ করার জন্য তাদের তৈরি করা হয়েছিল।
নাথান ওসমান

@ টনিডি ... বা তাদের একত্রিত করুন: মান অনুসারে একটি স্মার্ট পয়েন্টার ফিরিয়ে দিন। এইভাবে কলার এবং অনেক ক্ষেত্রে (যেমন make_shared/_uniqueব্যবহারযোগ্য) এখানে কলির কখনই প্রয়োজন হয় না newবা হয় না delete। এই উত্তরটি আসল পয়েন্টগুলি মিস করে: (ক) সি ++ আরভিও, মুভ শব্দার্থক এবং আউটপুট প্যারামিটারের মতো জিনিস সরবরাহ করে - যার প্রায়শই অর্থ হ'ল গতিশীলভাবে বরাদ্দ হওয়া মেমরি ফিরে আসার মাধ্যমে অবজেক্ট তৈরি করা এবং আজীবন বর্ধন অপ্রয়োজনীয় এবং গাফিল হয়ে যায়। (খ) এমনকি গতিশীল বরাদ্দের প্রয়োজনীয় পরিস্থিতিতেও, stdlib RAII মোড়ক সরবরাহ করে যা ব্যবহারকারীকে কুৎসিত অভ্যন্তরীণ বিশদটি থেকে মুক্তি দেয়।
আন্ডারস্কোর_ড

14

আপনি যখন নতুন ব্যবহার করেন তখন বস্তুগুলি গাদাতে বরাদ্দ দেওয়া হয়। আপনি যখন বিস্তারের প্রত্যাশা করেন তখন এটি সাধারণত ব্যবহৃত হয়। যখন আপনি কোনও বিষয় ঘোষণা করেন যেমন,

Class var;

এটি স্ট্যাকের উপর রাখা হয়।

আপনি সর্বদা নতুনটির সাথে যে স্তূপে স্থাপন করেছেন সেই বস্তুটিতে আপনাকে সর্বদা কল করতে হবে। এটি মেমরি ফাঁস হওয়ার সম্ভাবনা খুলে দেয়। স্ট্যাকের উপর স্থাপন করা বস্তুগুলি মেমরি ফাঁস হওয়ার প্রবণ নয়!


2
আপনি যখন প্রসারণের প্রত্যাশা করেন তখন +1 "[গাদা] সাধারণত ব্যবহৃত হয়" - যেমন একটি std::stringবা std::mapহ্যাঁ, তীক্ষ্ণ অন্তর্দৃষ্টি সংযোজন । আমার প্রাথমিক প্রতিক্রিয়া ছিল "তবে কোডের তৈরির সুযোগ থেকে কোনও বস্তুর আজীবন ডিকুল করার পক্ষেও খুব সাধারণভাবে", তবে সত্যই মূল্য দিয়ে ফিরে আসা বা অ- constরেফারেন্স বা পয়েন্টার দ্বারা কলার-স্কোপড মানগুলি গ্রহণ করা তার পক্ষে আরও ভাল, যদি "সম্প্রসারণ" জড়িত না হয় খুব। ফ্যাক্টরি পদ্ধতিগুলির মতো আরও কিছু শব্দ ব্যবহার রয়েছে যদিও ....
টনি ডেল্রয়

12

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

এটাই সেই সমস্যা যা মেমরিটি পুল করেTheতিহ্যবাহী হিপ বাস্তবায়নের অন্তর্নিহিত অসুবিধাগুলি প্রশমিত করার জন্য যেখানে সমাধানের জন্য তৈরি হয়েছে এখনও আপনাকে প্রয়োজনীয় হিসাবে গাদাটি ব্যবহার করার অনুমতি দেয়।

পুরোপুরি সমস্যা এড়াতে আরও ভাল। যদি আপনি এটি স্ট্যাকের উপর রাখতে পারেন, তবে এটি করুন।


আপনি সর্বদা যুক্তিসঙ্গতভাবে বিপুল পরিমাণ মেমরি বরাদ্দ করতে পারেন এবং তারপরে গতি যদি কোনও সমস্যা হয় তবে প্লেসমেন্ট নতুন / মুছুন।
rxantos

মেমরি পুলগুলি খণ্ডন এড়ানো, অবক্ষয়কে দ্রুত করা (কয়েক হাজার বস্তুর জন্য একটি অবলম্বন) করা এবং অধঃপতনকে আরও নিরাপদ করা।
লথার

10

আমি মনে করি পোস্টারটি তার You do not have to allocate everything on theheapচেয়ে বরং বলা উচিত stack

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


10

আমি নতুন "অত্যধিক" ব্যবহারের ধারণার সাথে একমত নই। যদিও সিস্টেমের ক্লাসগুলির সাথে নতুন পোস্টারটির মূল ব্যবহার কিছুটা হাস্যকর। ( int *i; i = new int[9999];? সত্যি? int i[9999];আমি মনে করি অনেক পরিস্কার হয়।) যে কি মন্তব্যকারীর ছাগল পেয়ে ছিল।

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

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


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

When you're working with your own classes/objects... আপনার প্রায়শই এটি করার কোনও কারণ নেই! Qs এর একটি ক্ষুদ্র অনুপাত দক্ষ কোডারদের দ্বারা ধারক ডিজাইনের বিশদগুলিতে রয়েছে। সম্পূর্ণ বিপরীতে, একটি দূর্বল অনুপাত হয় বা সক্রিয়ভাবে 'প্রোগ্রামিং' 'মাঠ', যেখানে একটি গৃহশিক্ষক দাবী তারা pointlessly চাকা reinvent মধ্যে ভয়াবহ বরাদ্দকরণ দেওয়া হয় - - আগে তারা এমনকি করেছি সংবাদে বিভ্রান্তি যারা জানেন না stdlib বিদ্যমান সম্পর্কে চাকা কী এবং কেন এটি কাজ করে তা শিখেছি । আরও বিমূর্ত বরাদ্দ প্রচার করে, সি ++ আমাদের সি এর অন্তহীন 'লিঙ্কযুক্ত তালিকার সেগফ্ল্ট' থেকে রক্ষা করতে পারে; দয়া করে, এটি দেওয়া যাক
আন্ডারস্কোর_ড

" সিস্টেম শ্রেণীর সাথে নতুন মূল পোস্টার ব্যবহার একটু হাস্যকর। ( int *i; i = new int[9999];? সত্যি? int i[9999];অনেক পরিস্কার হয়।)" হ্যাঁ, এটা পরিষ্কার, কিন্তু খেলা শয়তান এর উকিল করতে টাইপ অগত্যা একটি খারাপ যুক্তি নয়। 9999 উপাদানগুলির সাথে, আমি কল্পনা করতে পারি যে একটি কড়া এমবেডেড সিস্টেমের 9999 উপাদানগুলির জন্য পর্যাপ্ত পরিমাণে স্ট্যাক নেই: 9999x4 বাইট ~ 40 কেবি, এক্স 8 ~ 80 কেবি। সুতরাং, এই জাতীয় সিস্টেমগুলিকে গতিশীল বরাদ্দ ব্যবহার করার প্রয়োজন হতে পারে, ধরে নিয়ে তারা বিকল্প মেমরি ব্যবহার করে এটি প্রয়োগ করে। তবুও, এটি কেবল গতিশীল বরাদ্দকে ন্যায়সঙ্গত করতে পারে, না new; এ vectorক্ষেত্রে আসল সমাধান হবে
আন্ডারস্কোর_ড

@ বর্ষসেরা_ডির সাথে সম্মত হন - এটি এত বড় উদাহরণ নয়। আমি আমার স্ট্যাকের মতো 40,000 বা 80,000 বাইট যুক্ত করব না। আমি সম্ভবত এগুলি std::make_unique<int[]>()অবশ্যই স্তূপে বরাদ্দ করব ( অবশ্যই)।
einpoklum

3

দুটি কারণ:

  1. এই ক্ষেত্রে এটি অপ্রয়োজনীয়। আপনি আপনার কোডটিকে অযথা জটিল করে তুলছেন।
  2. এটি গাদা জায়গায় স্থান বরাদ্দ করে, এবং এর অর্থ হল যে আপনাকে deleteএটি পরে মনে রাখতে হবে, বা এটি একটি স্মৃতি ফাঁস হওয়ার কারণ হবে।

2

newনতুন goto

কেন gotoএতো আপত্তিজনক তা স্মরণ করুন : যদিও এটি প্রবাহ নিয়ন্ত্রণের জন্য একটি শক্তিশালী, নিম্ন-স্তরের সরঞ্জাম, লোকেরা প্রায়শই এটিকে অযথা জটিল উপায়ে ব্যবহার করে যা কোডটি অনুসরণ করা কঠিন করে তোলে difficult তদ্ব্যতীত, নিদর্শনগুলি পড়ার জন্য সবচেয়ে দরকারী এবং সহজতম কাঠামোগত প্রোগ্রামিং স্টেটমেন্টগুলিতে এনকোড করা হয়েছিল (যেমন forবা while); চূড়ান্ত প্রভাবটি হ'ল কোডটি যেখানে gotoযথাযথ উপায় তা বিরল, আপনি লেখার জন্য প্ররোচিত হলে আপনি gotoসম্ভবত খারাপ কাজ করছেন (যদি না আপনি সত্যিই জানেন যে আপনি কী করছেন)।

newঅনুরূপ - এটি প্রায়শই জিনিসগুলিকে অহেতুক জটিল এবং পড়া আরও শক্ত করে তুলতে ব্যবহৃত হয় এবং সর্বাধিক দরকারী ব্যবহারের ধরণগুলি এনকোড করা যায় বিভিন্ন শ্রেণিতে এনকোড করা হয়েছে। তদুপরি, আপনার যদি এমন কোনও নতুন ব্যবহারের ধরণ ব্যবহারের প্রয়োজন হয় যার জন্য ইতিমধ্যে মানক ক্লাস নেই, আপনি নিজের ক্লাস লিখতে পারেন যা সেগুলি এনকোড করে!

আমি এমনকি তর্ক করবে newহয় খারাপ চেয়ে goto, যুগল করার প্রয়োজনীয়তা কারণে newএবং deleteবিবৃতি।

যেমন goto, আপনি যদি কখনও মনে করেন যে আপনার ব্যবহারের প্রয়োজন হয় তবে আপনি newসম্ভবত খারাপ কাজ করছেন - বিশেষত যদি আপনি এমন কোনও শ্রেণীর প্রয়োগের বাইরে যা করছেন যার জীবনের উদ্দেশ্য হ'ল আপনার যা কিছু গতিশীল বরাদ্দ করা দরকার তা সজ্জিত করা।


এবং আমি যোগ করব: "আপনার মূলত এটির দরকার নেই"।
einpoklum

1

মূল কারণ হ'ল স্তূপযুক্ত বস্তুগুলি সর্বদা সহজ মানগুলির চেয়ে ব্যবহার এবং পরিচালনা করা কঠিন difficult রাইটিং কোড যা পড়া এবং বজায় রাখা সহজ হয় তা কোনও গুরুতর প্রোগ্রামারের সর্বদা প্রথম অগ্রাধিকার।

আর একটি দৃশ্য হ'ল আমরা যে লাইব্রেরিটি ব্যবহার করছি সেটি মূল্য শব্দার্থ সরবরাহ করে এবং গতিশীল বরাদ্দকে অপ্রয়োজনীয় করে তোলে। Std::stringএকটি ভাল উদাহরণ।

তবে অবজেক্ট অরিয়েন্টেড কোডের জন্য, পয়েন্টার ব্যবহার করা - যার অর্থ newএটি আগে তৈরি করার জন্য - এটি অবশ্যই আবশ্যক। রিসোর্স ম্যানেজমেন্টের জটিলতা সহজ করার জন্য আমাদের স্মার্ট পয়েন্টারগুলির মতো এটি যথাসম্ভব সহজ করে তোলার জন্য কয়েক ডজন সরঞ্জাম রয়েছে। অবজেক্ট ভিত্তিক দৃষ্টান্ত বা জেনেরিক দৃষ্টান্ত মান শব্দার্থক ধারনা করে এবং newঅন্য কোথাও পোস্টারগুলি যেমন বলেছিল ঠিক তেমনই কম বা না প্রয়োজন ।

Typতিহ্যবাহী নকশার ধরণগুলি, বিশেষত GoF বইয়ে উল্লিখিত new, তারা প্রচুর পরিমাণে ব্যবহার করে , কারণ এগুলি সাধারণত ওও কোড।


4
এটি একটি অসাধারণ উত্তর। For object oriented code, using a pointer [...] is a must: বাজে কথা । আপনি একটি ছোট উপসেট একমাত্র উল্লেখ দ্বারা 'OO যেমন পণ্য' devaluing হয়, পলিমরফিজম - এছাড়াও আজেবাজে কথা: রেফারেন্স খুব কাজ করে। [pointer] means use new to create it beforehand: বিশেষত আজেবাজে : রেফারেন্স বা পয়েন্টারগুলি স্বয়ংক্রিয়ভাবে বরাদ্দ হওয়া অবজেক্টগুলিতে নেওয়া যেতে পারে এবং বহুগুণিতভাবে ব্যবহৃত হয়; আমাকে পাহারা[typical OO code] use new a lot: হয়তো কোনও পুরানো বইয়ে, তবে কে পাত্তা দেয়? অস্পষ্ট যে কোনও আধুনিক সি ++ এছিউ new/ কাঁচা পয়েন্টার যেখানেই সম্ভব - এবং এটি করে
আন্ডারস্কোর_ড

1

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

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

অবশ্যই এটি নিয়মের ব্যতিক্রম মাত্র।


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