সি ++ অবজেক্ট ইনস্ট্যান্টেশন


113

আমি একজন সি প্রোগ্রামার সি ++ বোঝার চেষ্টা করছি। অনেক টিউটোরিয়াল যেমন একটি স্নিপেট ব্যবহার করে অবজেক্ট ইনস্ট্যান্টেশন প্রদর্শন করে:

Dog* sparky = new Dog();

যা ইঙ্গিত দেয় যে পরে আপনি এটি করবেন:

delete sparky;

যা বোঝায়। এখন, গতিশীল মেমরির বরাদ্দ অপ্রয়োজনীয় ক্ষেত্রে, পরিবর্তে উপরেরটি ব্যবহার করার কোনও কারণ আছে কি?

Dog sparky;

এবং একবার কি স্পার্কি সুযোগের বাইরে চলে গেলে ধ্বংসকারীকে ডাকা হয়?

ধন্যবাদ!

উত্তর:


166

বিপরীতে, আপনার সর্বদা স্ট্যাক বরাদ্দের পছন্দ করা উচিত, যে পরিমাণে থাম্বের নিয়ম হিসাবে আপনার ব্যবহারকারীর কোডে কখনও নতুন / মুছে ফেলা উচিত নয়।

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

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

এই প্রতিমাটির সর্বাধিক প্রচলিত নাম হ'ল RAII

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

অনেক টিউটোরিয়াল যেমন একটি স্নিপেট ব্যবহার করে অবজেক্ট ইনস্ট্যান্টেশন প্রদর্শন করে ...

সুতরাং আপনি যা আবিষ্কার করেছেন তা হল বেশিরভাগ টিউটোরিয়াল স্তন্যপান করে। ;) বেশিরভাগ টিউটোরিয়ালগুলি আপনাকে প্রয়োজন হয় না যখন ভেরিয়েবল তৈরি করতে নতুন / মুছুন কল করা এবং আপনার বরাদ্দগুলির আজীবন ট্র্যাকিংয়ের জন্য একটি কঠিন সময় প্রদান সহ লাউ সি ++ অনুশীলনগুলি শেখায়।


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

2
এটি একটি সঠিক উত্তর, তবে স্ট্যাকের উপর বস্তু তৈরির অভ্যাসে আমি কখনই প্রবেশ করতে পারব না কারণ এটি কখনই স্পষ্টভাবে স্পষ্ট হয় না যে বস্তুটি কত বড় হবে। আপনি কেবল স্ট্যাক-ওভারফ্লো ব্যতিক্রম চাইছেন।
dviljoen

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

3
@ ডিভিলজোয়েন: না আমি নেই। সি ++ সংকলকগুলি অযৌক্তিকভাবে বস্তুগুলি প্রসারণ করে না। আপনি দেখতে পাবেন সবচেয়ে খারাপটি সাধারণত এটি চারটি বাইটের নিকটতম একাধিক পর্যন্ত গোল হয়ে যায়। সাধারণত, একটি পয়েন্টারযুক্ত একটি শ্রেণি পয়েন্টার হিসাবে নিজেই যতটা জায়গা নেয়, তাই স্ট্যাকের ব্যবহারে আপনার কোনও মূল্য লাগে না।
জলফ

20

স্ট্যাকের জিনিসগুলি বরাদ্দ এবং স্বয়ংক্রিয়ভাবে মুক্ত করার ক্ষেত্রে একটি সুবিধা হতে পারে যদিও এর কিছু অসুবিধা রয়েছে।

  1. আপনি স্ট্যাকের উপর বিশাল বস্তু বরাদ্দ করতে নাও চান।

  2. গতিশীল প্রেরণ! এই কোডটি বিবেচনা করুন:

#include <iostream>

class A {
public:
  virtual void f();
  virtual ~A() {}
};

class B : public A {
public:
  virtual void f();
};

void A::f() {cout << "A";}
void B::f() {cout << "B";}

int main(void) {
  A *a = new B();
  a->f();
  delete a;
  return 0;
}

এটি "বি" মুদ্রণ করবে। এখন স্ট্যাক ব্যবহার করার পরে কী ঘটে তা দেখা যাক:

int main(void) {
  A a = B();
  a.f();
  return 0;
}

এটি "এ" মুদ্রণ করবে, যা জাভা বা অন্যান্য অবজেক্ট ওরিয়েন্টেড ভাষার সাথে পরিচিত তাদের পক্ষে স্বজ্ঞাত হতে পারে না। কারণটি হ'ল আপনার Bআর কোনও উদাহরণের পয়েন্টার নেই। পরিবর্তে, এর উদাহরণ Bতৈরি করা যায় এবং aপ্রকারের ভেরিয়েবলের অনুলিপি করা হয় A

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


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

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

@ আসরে_আমি সম্মত; এই উত্তরের শেষ অনুচ্ছেদটি সরানো উচিত। আমি এই উত্তরটি সম্পাদিত করেছিলাম এর অর্থ এই নয় যে এটির সাথে আমি একমত; আমি কেবল এটির ভুলগুলি পড়তে চাইনি।
TamaMcGlinn

@ টামাএমসিগ্লিন সম্মত হয়েছে। ভাল সম্পাদনার জন্য ধন্যবাদ। আমি মতামত অংশ অপসারণ।
ইউনিভার্স

13

ঠিক আছে, পয়েন্টারটি ব্যবহার করার কারণটি হ'ল ম্যালোকের সাথে বরাদ্দ করা সিতে পয়েন্টার ব্যবহার করার কারণটি: আপনি যদি চান যে আপনার বস্তুটি আপনার ভেরিয়েবলের চেয়ে বেশি দিন বেঁচে থাকে!

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


13

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

void FeedTheDog(Dog* hungryDog);

Dog* badDog = new Dog;
FeedTheDog(badDog);
delete badDog;

Dog goodDog;
FeedTheDog(&goodDog);

বিকল্পভাবে: অকার্যকর FeedTheDog (কুকুর এবং ক্ষুধার্ত ডগ); কুকুর কুকুর; FeedTheDog (কুকুর);
স্কট ল্যাংহ্যাম

1
@ স্কটল্যাংহ্যাম সত্য, তবে আমি যে বিন্দুটি তৈরি করার চেষ্টা করছিলাম সেটি ছিল না। কখনও কখনও আপনি একটি ফাংশন কল করছেন যা উদাহরণস্বরূপ একটি Nচ্ছিক NULL পয়েন্টার নেয়, বা সম্ভবত এটি একটি বিদ্যমান এপিআই যা পরিবর্তন করা যায় না।
মার্ক র্যানসোম

7

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

(1)। ব্যতিক্রমগুলির ক্ষেত্রে স্ট্যাক আনওয়াইন্ডিং সম্পর্কে আপনাকে চিন্তা করার দরকার নেই

(2)। আপনার হিপ ম্যানেজারের দ্বারা প্রয়োজনের চেয়ে বেশি জায়গা বরাদ্দ করার কারণে আপনার মেমরি বিভাজন সম্পর্কে চিন্তা করার দরকার নেই।


1
বস্তুর আকার সম্পর্কে কিছুটা বিবেচনা করা উচিত। স্ট্যাকটি আকার সীমিত, সুতরাং খুব বড় অবজেক্টগুলি হ্যাপ বরাদ্দ করা উচিত।
অ্যাডাম

1
@ অ্যাডাম আমার মনে হয় নবীন এখানে এখনও ঠিক আছেন। যদি আপনি স্ট্যাকের উপর একটি বড় অবজেক্ট রাখতে পারেন, তবে এটি করুন, কারণ এটি আরও ভাল। অনেকগুলি কারণ রয়েছে যা আপনি সম্ভবত পারবেন না। তবে আমার ধারণা তিনি সঠিক's
ম্যাককে

5

আমি কেবল উদ্বিগ্ন হওয়ার কারণেই হ'ল কুকুরটি এখন স্তূপের চেয়ে স্ট্যাকের জন্য বরাদ্দ করা হয়েছে। সুতরাং কুকুরটি যদি আকারে মেগাবাইট হয় তবে আপনার সমস্যা হতে পারে,

আপনার যদি নতুন / মোছার রুট যেতে হয় তবে ব্যতিক্রম থেকে সাবধান থাকুন। এবং এই কারণে আপনার নিজের জীবনযাত্রাটি পরিচালনা করতে অটো_পিটার বা একটি বুস্ট স্মার্ট পয়েন্টার ধরণের একটি ব্যবহার করা উচিত।


1

আপনি যখন স্ট্যাকের উপর বরাদ্দ করতে পারবেন তখন নতুন (গাদাতে) কোনও কারণ নেই (যদি কোনও কারণে আপনি একটি ছোট স্ট্যাক পেয়ে থাকেন এবং গাদাটি ব্যবহার করতে চান না তবে)।

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


প্রচুর কারণ রয়েছে, উদাহরণস্বরূপ, আমাকে উত্তর দেখুন।
বিপজ্জনক দিন

আমি মনে করি আপনি হয়ত এই জিনিসটির ফাংশনটির সুযোগটি ছড়িয়ে দিতে চাইবেন, কিন্তু ওপি তাদের পরামর্শ দেওয়ার মতো বলে মনে হয়নি।
স্কট ল্যাংহাম

0

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


2
আপনি পলিম্পোরিকভাবে স্ট্যাক ভিত্তিক অবজেক্টগুলির সাথেও কাজ করতে পারেন, আমি এই বিষয়ে স্ট্যাক / এবং হ্যাপ বরাদ্দকৃত বস্তুর মধ্যে কোনও পার্থক্য দেখছি না। যেমন: অকার্যকর MyFunc () {কুকুর কুকুর; কুকুর প্রতিপালন করা); } অকার্যকর ফিড (প্রাণী ও প্রাণী) {অটো ফুড = প্রাণী-> গেটফ্যাওয়ারাইটফুড (); PutFoodInBowl (খাদ্য); } // এই উদাহরণে GetFavouriteFood একটি ভার্চুয়াল ফাংশন হতে পারে যা প্রতিটি প্রাণী তার নিজস্ব প্রয়োগের সাথে ওভাররাইড করে। এটি কোনও জড়িত জড়িত না দিয়ে বহুবিধভাবে কাজ করবে।
স্কট ল্যাংহ্যাম

-1: পলিমারফিজমে কেবল একটি রেফারেন্স বা পয়েন্টার প্রয়োজন; এটি অন্তর্নিহিত দৃষ্টান্তের স্টোরেজ সময়কালের সম্পূর্ণ অজ্ঞানী।
আন্ডারস্কোর_ড

@undcore_d "সার্বজনীন বেস শ্রেণি ব্যবহার করা ব্যয় বোঝায়: পলিমারফিক হওয়ার জন্য অবজেক্টগুলি গাদা-বরাদ্দ করতে হবে;" - বজরেন স্ট্রাউটস্ট্রপ স্ট্রোস্ট্রুপ.com /
বিপজ্জনকদ্বারা

এলএল, স্ট্রস্ট্রুপ নিজেই এটি বলেছেন কিনা তা আমি খেয়াল করি না, তবে এটি তাঁর জন্য অবিশ্বাস্যরকম বিব্রতকর একটি উক্তি, কারণ তিনি ভুল। এটি নিজে পরীক্ষা করা শক্ত নয়, আপনি জানেন: স্ট্যাকের উপর কিছু ডেরিভাডা, ডেরিভডবি এবং ডেরিভডিসি ইনস্ট্যান্ট করুন; বেসে একটি স্ট্যাক-বরাদ্দ পয়েন্টার ইনস্ট্যান্ট করুন এবং নিশ্চিত করুন যে আপনি এটি এ / বি / সি দিয়ে সিট করতে পারেন এবং সেগুলি বহুবর্ষীয়ভাবে ব্যবহার করতে পারেন। দাবিগুলির ক্ষেত্রে সমালোচনা চিন্তাভাবনা এবং মানক রেফারেন্স প্রয়োগ করুন, এমনকি তারা ভাষার মূল লেখক যদি থাকেন। এখানে: স্ট্যাকওভারফ্লো.com
আন্ডারস্কোর_ডি

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

-4

ভিজ্যুয়াল স্টুডিওতেও আমার একই সমস্যা ছিল। আপনাকে ব্যবহার করতে হবে:

yourClass-> classMethod ();

বরং:

yourClass.classMethod ();


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