আমি কেন নিজের পয়েন্টারটির চেয়ে পয়েন্টার ব্যবহার করব?


1597

আমি জাভা ব্যাকগ্রাউন্ড থেকে আসছি এবং সি ++ এ অবজেক্টের সাথে কাজ শুরু করেছি। তবে একটি জিনিস আমার কাছে ঘটেছিল তা হ'ল লোকেরা প্রায়শই বস্তুগুলির পরিবর্তে বস্তুগুলিতে পয়েন্টার ব্যবহার করে, উদাহরণস্বরূপ এই ঘোষণা:

Object *myObject = new Object;

বরং:

Object myObject;

বা কোনও ফাংশন ব্যবহারের পরিবর্তে testFunc(), এর মতো বলি :

myObject.testFunc();

আমাদের লিখতে হবে:

myObject->testFunc();

তবে কেন আমরা এইভাবে এটি করা উচিত তা আমি বুঝতে পারি না। আমি ধরে নেব এটি দক্ষতা এবং গতির সাথেই করতে হবে যেহেতু আমরা মেমরি ঠিকানায় সরাসরি অ্যাক্সেস পাই। আমি কি সঠিক?


403
আপনাকে এই অনুশীলনটি অনুসরণ না করে কেবল অনুশীলন সম্পর্কে প্রশ্ন করার জন্য কুডোস। বেশিরভাগ সময় পয়েন্টারগুলি অতিরিক্ত ব্যবহৃত হয়।
লুচিয়ান গ্রিগোর

118
আপনি যদি পয়েন্টার ব্যবহার করার কোনও কারণ না দেখেন তবে করবেন না। বস্তু পছন্দ। কাঁচা পয়েন্টারগুলির আগে ভাগ করা_প্ট্রির আগে অনন্য_পিটরের আগে অবজেক্টগুলিকে পছন্দ করুন।
স্টিফান

111
দ্রষ্টব্য: জাভাতে, সমস্ত কিছু (মূল ধরণের ব্যতীত) একটি পয়েন্টার। সুতরাং আপনি বরং বিপরীত জিজ্ঞাসা করা উচিত: কেন আমার সহজ জিনিস প্রয়োজন?
করলি হরভথ

117
নোট করুন যে, জাভাতে পয়েন্টারগুলি সিনট্যাক্স দ্বারা লুকিয়ে রয়েছে। সি ++ এ, পয়েন্টার এবং একটি পয়েন্টারবিহীন মধ্যে পার্থক্য কোডে স্পষ্ট করে দেওয়া হয়। জাভা সর্বত্র পয়েন্টার ব্যবহার করে।
ড্যানিয়েল মার্টন

214
খুব প্রশস্ত হিসাবে বন্ধ ? সিরিয়াসলি? দয়া করে লোকেরা, নোট করুন যে এই জাভা ++ প্রোগ্রামিংয়ের পদ্ধতিটি খুব সাধারণ এবং সি ++ সম্প্রদায়ের অন্যতম গুরুত্বপূর্ণ সমস্যা । এটি গুরুত্ব সহকারে চিকিত্সা করা উচিত।
মনু 343726

উত্তর:


1570

এটি খুব দুর্ভাগ্য যে আপনি প্রায়শই গতিশীল বরাদ্দ দেখতে পান। এটি কেবল দেখায় যে সেখানে কতগুলি খারাপ সি ++ প্রোগ্রামার রয়েছে।

এক অর্থে, আপনার দুটি প্রশ্ন এক হয়ে গেছে। প্রথমটি হ'ল কখন আমাদের গতিশীল বরাদ্দ (ব্যবহার new) ব্যবহার করা উচিত ? দ্বিতীয়টি হল কখন আমাদের পয়েন্টার ব্যবহার করা উচিত?

গৃহস্থালির গুরুত্বপূর্ণ বার্তাটি হ'ল আপনার কাজের জন্য সর্বদা উপযুক্ত সরঞ্জামটি ব্যবহার করা উচিত । প্রায় সমস্ত পরিস্থিতিতে ম্যানুয়াল গতিশীল বরাদ্দ সম্পাদন এবং / বা কাঁচা পয়েন্টার ব্যবহারের চেয়ে আরও উপযুক্ত এবং নিরাপদ কিছু রয়েছে।

গতিশীল বরাদ্দ

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

যে দুটি প্রধান পরিস্থিতিতে আপনার গতিশীল বরাদ্দ প্রয়োজন হতে পারে:

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

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

পয়েন্টার

তবে গতিশীল বরাদ্দের বাইরে কাঁচা পয়েন্টারগুলির জন্য আরও সাধারণ ব্যবহার রয়েছে তবে বেশিরভাগের বিকল্প রয়েছে যা আপনার পছন্দ করা উচিত। আগের মতো, আপনার পয়েন্টারের প্রয়োজন না হলে বিকল্পগুলি সর্বদা পছন্দ করুন

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

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

  3. আপনি প্রতিনিধিত্ব করতে চান যেnullptr যখন কোনও বস্তু বাদ দেওয়া হচ্ছে তখন তাকে কোনও পাস করার অনুমতি দিয়ে objectচ্ছিক। যদি এটি একটি যুক্তি হয় তবে আপনার ডিফল্ট আর্গুমেন্ট বা ফাংশন ওভারলোডগুলি ব্যবহার করতে পছন্দ করা উচিত। অন্যথায়, আপনি পছন্দসইভাবে এমন একটি আচরণ ব্যবহার করুন যা এই আচরণকে সজ্জিত করে, যেমন std::optional(সি ++ 17 - প্রারম্ভিক সি ++ স্ট্যান্ডার্ড সহ ব্যবহার boost::optional)।

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

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


82
"আপনার বর্তমান সুযোগটি বহির্মুখী করার জন্য আপনার অবজেক্টটির প্রয়োজন" " - এটি সম্পর্কে একটি অতিরিক্ত নোট: এমন কিছু ঘটনা রয়েছে যা দেখে মনে হয় আপনার বর্তমান সুযোগটি বহন করার জন্য আপনার প্রয়োজন হবে, তবে আপনি আসলে তা করেন না। যদি আপনি আপনার বস্তুকে কোনও ভেক্টরের ভিতরে রাখেন, উদাহরণস্বরূপ, অবজেক্টটি ভেক্টরটিতে অনুলিপি করা হবে (বা সরানো) হবে এবং মূল অবজেক্টটি তার স্কোপ শেষ হয়ে গেলে ধ্বংস করতে নিরাপদ is

25
মনে রাখবেন যে এখন অনেক জায়গায় এস / কপি / মুভ / চলে। কোনও জিনিস প্রত্যাবর্তন অবশ্যই একটি পদক্ষেপ বোঝায় না। আপনার এও লক্ষ করা উচিত যে কোনও পয়েন্টারের মাধ্যমে কোনও অ্যাক্সেস অ্যাক্সেস করা কীভাবে এটি তৈরি হয়েছিল তা অরথোগোনাল।
কুকুরছানা

15
আমি এই উত্তরে আরআইআইয়ের একটি স্পষ্ট উল্লেখ মিস করি। সি ++ হ'ল রিসোর্স ম্যানেজমেন্ট সম্পর্কে (প্রায় সমস্ত), আর আরআইআই হ'ল সি ++ (এবং মূল সমস্যা যা কাঁচা পয়েন্টার উত্পন্ন করে: ব্রেকিং
আরএআইআই

11
সি ++ 11 এর আগে স্মার্ট পয়েন্টারগুলির অস্তিত্ব ছিল, যেমন বুস্ট :: শেয়ার্ড_পিটার এবং বুস্ট :: স্কোপড_পিটিআর। অন্যান্য প্রকল্পগুলির নিজস্ব সমতুল্য রয়েছে। আপনি চলন্ত শব্দার্থবিজ্ঞান পেতে পারেন না, এবং স্ট্যান্ড :: অটো_পিটারের কার্যভার ত্রুটিযুক্ত, সুতরাং সি ++ 11 জিনিসগুলিকে উন্নত করে, তবে পরামর্শটি এখনও ভাল। (এবং একটি দু: খিত নিতপিক, এটি একটি সি ++ 11 সংকলক অ্যাক্সেস যথেষ্ট নয় , এটি প্রয়োজনীয় যে সমস্ত সংকলক আপনি সম্ভবত আপনার কোডটি সি ++ 11 সমর্থন করে কাজ করতে চান Yes হ্যাঁ, ওরাকল সোলারিস স্টুডিও, আমি আপনাকে দেখছি।)
আরব

7
@ MDMoore313 আপনি লিখতে পারেনObject myObject(param1, etc...)
user000001

171

পয়েন্টারগুলির জন্য অনেকগুলি ব্যবহারের কেস রয়েছে।

বহুরুপী আচরণ । পলিমারফিক ধরণের জন্য, পয়েন্টারগুলি (বা রেফারেন্স) কাটা এড়ানোর জন্য ব্যবহৃত হয়:

class Base { ... };
class Derived : public Base { ... };

void fun(Base b) { ... }
void gun(Base* b) { ... }
void hun(Base& b) { ... }

Derived d;
fun(d);    // oops, all Derived parts silently "sliced" off
gun(&d);   // OK, a Derived object IS-A Base object
hun(d);    // also OK, reference also doesn't slice

শব্দার্থবিজ্ঞানের উল্লেখ এবং অনুলিপি এড়ানো । পলিমারফিক জাতীয় ধরণের জন্য, একটি পয়েন্টার (বা একটি রেফারেন্স) সম্ভাব্য ব্যয়বহুল অবজেক্টটি অনুলিপি করা এড়াবে will

Base b;
fun(b);  // copies b, potentially expensive 
gun(&b); // takes a pointer to b, no copying
hun(b);  // regular syntax, behaves as a pointer

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

রিসোর্স অধিগ্রহণnewঅপারেটরটি ব্যবহার করে কোনও উত্সটিতে একটি পয়েন্টার তৈরি করা আধুনিক সি ++ এর একটি অ্যান্টি-প্যাটার্ন । একটি বিশেষ সংস্থান শ্রেণী (স্ট্যান্ডার্ড ধারকগুলির মধ্যে একটি) বা স্মার্ট পয়েন্টার ( std::unique_ptr<>বা std::shared_ptr<>) ব্যবহার করুন। বিবেচনা:

{
    auto b = new Base;
    ...       // oops, if an exception is thrown, destructor not called!
    delete b;
}

বনাম

{
    auto b = std::make_unique<Base>();
    ...       // OK, now exception safe
}

কোনও কাঁচা পয়েন্টার কেবলমাত্র "ভিউ" হিসাবে ব্যবহার করা উচিত এবং কোনওভাবেই মালিকানার সাথে জড়িত নয়, তা সরাসরি নির্মাণের মাধ্যমেই হোক বা প্রত্যাবর্তন মূল্যের মাধ্যমেই হোক। সি ++ এফএকিউ থেকে এই প্রশ্নোত্তরও দেখুন ।

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


17
"একটি সম্পদ নতুন অপারেটর ব্যবহার করে একটি পয়েন্টার তৈরি বিরোধী প্যাটার্ন হল" আমার মনে হয় আপনি এমনকি যে উন্নত করতে পারে একটি কাঁচা পয়েন্টার থাকার নিজের কিছু বিরোধী প্যাটার্ন । কেবল সৃষ্টি নয়, কাঁচা পয়েন্টারগুলি আর্গুমেন্ট বা রিটার্ন মান হিসাবে বোঝাচ্ছে মালিকানা হস্তান্তরকে বোঝায় আইএমএইচও unique_ptr/ পদক্ষেপ শব্দার্থিকের পরে
অবহিত করা হয়েছে

1
@dyp টিএনএক্স, আপডেট হয়েছে এবং এই বিষয়ে সি ++ এফএকিউ প্রশ্নোত্তর রেফারেন্স।
TemplateRex

4
স্মার্ট পয়েন্টার সর্বত্র ব্যবহার করা একটি বিরোধী-নিদর্শন। কয়েকটি প্রযোজ্য ক্ষেত্রে এটি প্রযোজ্য তবে বেশিরভাগ সময় গতিশীল বরাদ্দ (স্বেচ্ছাসেবক আজীবন) জন্য যে একই যুক্তিটি সাধারণ স্মার্ট পয়েন্টারগুলির সাথেও বিতর্ক করে।
জেমস কানজে

2
@ জামেসকানজে আমি বোঝাতে চাইনি যে স্মার্ট পয়েন্টারগুলি কেবলমাত্র মালিকানার জন্য, এবং কাঁচা পয়েন্টারগুলি মালিকানার জন্য ব্যবহার করা উচিত নয়, কেবল দেখার জন্য।
TemplateRex

2
@ টেম্পলেটআরেক্স এটি কিছুটা নির্বোধ বলে মনে হচ্ছে যা hun(b)আপনাকে স্বাক্ষরের জ্ঞান প্রয়োজন যদি না আপনি সংকলন না হওয়া পর্যন্ত ভুল প্রকারটি সরবরাহ করেন না তা জেনেও ভাল না হন। রেফারেন্স ইস্যুটি সাধারণত সংকলনের সময় ধরা পড়বে না এবং ডিবাগ করার জন্য আরও বেশি প্রচেষ্টা নেবে, আপনি যদি আর্গুমেন্টটি সঠিক কিনা তা নিশ্চিত করার জন্য স্বাক্ষরটি পরীক্ষা করে দেখলে আপনিও যুক্তিগুলির কোনও রেফারেন্স কিনা তা দেখতে সক্ষম হবেন সুতরাং রেফারেন্স বিট একটি অ-সমস্যার কিছু হয়ে যায় (বিশেষত যখন আইডিই বা টেক্সট সম্পাদকদের ব্যবহার করে যা নির্বাচিত ফাংশনগুলির স্বাক্ষর দেখায়)। এছাড়াও const&,।
জাব

130

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

দুটি ভাষার তুলনায় পরিস্থিতিটি পরীক্ষা করা যাক:

জাভা:

Object object1 = new Object(); //A new object is allocated by Java
Object object2 = new Object(); //Another new object is allocated by Java

object1 = object2; 
//object1 now points to the object originally allocated for object2
//The object originally allocated for object1 is now "dead" - nothing points to it, so it
//will be reclaimed by the Garbage Collector.
//If either object1 or object2 is changed, the change will be reflected to the other

এর নিকটতম সমতুল্য:

সি ++:

Object * object1 = new Object(); //A new object is allocated on the heap
Object * object2 = new Object(); //Another new object is allocated on the heap
delete object1;
//Since C++ does not have a garbage collector, if we don't do that, the next line would 
//cause a "memory leak", i.e. a piece of claimed memory that the app cannot use 
//and that we have no way to reclaim...

object1 = object2; //Same as Java, object1 points to object2.

আসুন বিকল্প সি ++ উপায় দেখুন:

Object object1; //A new object is allocated on the STACK
Object object2; //Another new object is allocated on the STACK
object1 = object2;//!!!! This is different! The CONTENTS of object2 are COPIED onto object1,
//using the "copy assignment operator", the definition of operator =.
//But, the two objects are still different. Change one, the other remains unchanged.
//Also, the objects get automatically destroyed once the function returns...

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

জাভা:

int object1; //An integer is allocated on the stack.
int object2; //Another integer is allocated on the stack.
object1 = object2; //The value of object2 is copied to object1.

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

হোম পয়েন্ট নিন - Object * object = new Object()নির্মাণটি আসলে যা সাধারণত জাভা (বা সেই বিষয়ে সি #) শব্দার্থবিজ্ঞানের সবচেয়ে নিকটতম।


7
Object2 is now "dead": আমি মনে করি আপনি বোঝাতে চেয়েছেন myObject1বা আরও সুনির্দিষ্টভাবে the object pointed to by myObject1
ক্লিমেট

2
প্রকৃতপক্ষে! কিছুটা রিপ্রাসড।
গেরাসিমোস আর

2
Object object1 = new Object(); Object object2 = new Object();খুব খারাপ কোড। দ্বিতীয় নতুন বা দ্বিতীয় অবজেক্ট কনস্ট্রাক্টর নিক্ষেপ করতে পারে এবং এখন অবজেক্ট 1 ফাঁস হয়ে গেছে। আপনি যদি কাঁচা newগুলি ব্যবহার করে থাকেন তবে আপনাকে newএআইএসআই র‌্যাপারগুলিতে ASAP মোড়ানো উচিত ।
পিএসকোকিক

8
প্রকৃতপক্ষে, এটি হ'ল এটি যদি কোনও প্রোগ্রাম ছিল এবং এর চারপাশে আর কিছুই চলছিল না। ধন্যবাদ, এটি কেবলমাত্র একটি ব্যাখ্যা স্নিপেট দেখায় যে সি ++ তে পয়েন্টার কীভাবে আচরণ করে - এবং যে কয়েকটি স্থানে একটি RAII বস্তু কাঁচা পয়েন্টারের পরিবর্তে প্রতিস্থাপন করা যায় না, সেগুলি কাঁচা পয়েন্টার সম্পর্কে অধ্যয়ন এবং শিখছে ...
গেরাসিমোস আর

80

পয়েন্টার ব্যবহারের আর একটি ভাল কারণ হ'ল ফরোয়ার্ড ঘোষণার জন্য । একটি বৃহত যথেষ্ট প্রকল্পে তারা সত্যই সংকলন সময়ের গতি বাড়িয়ে তুলতে পারে।


7
এটি সত্যিই দরকারী তথ্যের মিশ্রণে যুক্ত হচ্ছে, তাই আপনি খুশি হয়ে উত্তর দিয়েছেন!
TemplateRex

3
std :: shared_ptr <T> এছাড়াও টি এর সামনে ঘোষণার সাথে কাজ করে (স্ট্যান্ড :: অনন্য_প্রতি <টি> না )
বার্কাস

13
@ বার্কাস: এর অগ্রিম std::unique_ptr<T>ঘোষণার সাথে কাজ করে T। আপনাকে কেবল এটি নিশ্চিত করতে হবে যে যখন ডেস্ট্রাক্টর std::unique_ptr<T>ডাকা হয় তখন এটি Tএকটি সম্পূর্ণ ধরণের। এর অর্থ সাধারণত আপনার শ্রেণীর অন্তর্ভুক্ত যা std::unique_ptr<T>শিরোনাম ফাইলটিতে এটির ডেস্ট্রাক্টর ঘোষণা করে এবং এটি সিপিপি ফাইলে প্রয়োগ করে (বাস্তবায়ন ফাঁকা থাকলেও)।
ডেভিড স্টোন

মডিউলগুলি এটি ঠিক করবে?
ট্রেভর হিকি

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

78

মুখবন্ধ

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

সামনে আমরা যাই

তবে কেন আমরা এইভাবে এটি করা উচিত তা আমি বুঝতে পারি না। আমি ধরে নেব এটি দক্ষতা এবং গতির সাথেই করতে হবে যেহেতু আমরা মেমরি ঠিকানায় সরাসরি অ্যাক্সেস পাই। আমি কি সঠিক?

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

{
    std::string s;
}
// s is destroyed here

অন্যদিকে, আপনি যদি গতিশীলভাবে বরাদ্দকৃত পয়েন্টার ব্যবহার করেন তবে এর ডেস্ট্রাক্টরকে ম্যানুয়ালি কল করতে হবে। deleteএই ধ্বংসকারীকে আপনার জন্য কল করে।

{
    std::string* s = new std::string;
}
delete s; // destructor called

newসি # এবং জাভাতে প্রচলিত সিনট্যাক্সের সাথে এর কোনও যোগসূত্র নেই। এগুলি সম্পূর্ণ ভিন্ন উদ্দেশ্যে ব্যবহৃত হয়।

গতিশীল বরাদ্দের সুবিধা

1. আপনাকে আগে থেকে অ্যারের আকার জানতে হবে না

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

char buffer[100];
std::cin >> buffer;
// bad input = buffer overflow

অবশ্যই, যদি আপনি এর std::stringপরিবর্তে ব্যবহার করেন তবে std::stringঅভ্যন্তরীণভাবে নিজেকে পুনরায় আকার দেয় যাতে কোনও সমস্যা না হয়। তবে মূলত এই সমস্যার সমাধান হ'ল গতিশীল বরাদ্দ। আপনি ব্যবহারকারীর ইনপুট উপর ভিত্তি করে গতিশীল মেমরি বরাদ্দ করতে পারেন, উদাহরণস্বরূপ:

int * pointer;
std::cout << "How many items do you need?";
std::cin >> n;
pointer = new int[n];

পার্শ্ব দ্রষ্টব্য : বহু প্রাথমিকের এক ভুলটি হ'ল পরিবর্তনশীল দৈর্ঘ্যের অ্যারে ব্যবহার। এটি একটি জিএনইউ এক্সটেনশন এবং ঝনঝনায় একটি কারণ তারা জিসিসির অনেকগুলি এক্সটেনশানকে মিরর করে। সুতরাং নিম্নলিখিত int arr[n]উপর নির্ভর করা উচিত নয়।

গাদা স্ট্যাকের চেয়ে অনেক বড়, যেহেতু তার নিজের প্রয়োজন মতো মেমরি নির্বিচারে বরাদ্দ / পুনর্বিবেচনা করতে পারে, অন্যদিকে স্ট্যাকের সীমাবদ্ধতা রয়েছে।

2. অ্যারে পয়েন্টার নয়

এটি কীভাবে আপনি জিজ্ঞাসা একটি সুবিধা? অ্যারে এবং পয়েন্টারগুলির পিছনে বিভ্রান্তি / পৌরাণিক কাহিনী বুঝতে পারলে উত্তরটি পরিষ্কার হয়ে যাবে। সাধারণত ধারণা করা হয় যে এগুলি একই, তবে তারা তা নয়। এই পৌরাণিক কাহিনীটি এ থেকে আসে যে পয়েন্টারগুলি ঠিক অ্যারেগুলির মতো সাবস্ক্রিপশন করা যায় এবং কোনও ক্রয়ের ঘোষণায় শীর্ষ স্তরের পয়েন্টারগুলিতে অ্যারে ক্ষয় হওয়ার কারণে of যাইহোক, একবার অ্যারে কোনও পয়েন্টারের সিদ্ধান্ত নেয়, পয়েন্টারটি তার sizeofতথ্য হারিয়ে ফেলে । সুতরাং sizeof(pointer)বাইটগুলিতে পয়েন্টারের আকার দেবে যা সাধারণত 64৪-বিট সিস্টেমে 8 বাইট হয়।

আপনি অ্যারেগুলিকে বরাদ্দ করতে পারবেন না, কেবল তাদের আরম্ভ করুন। উদাহরণ স্বরূপ:

int arr[5] = {1, 2, 3, 4, 5}; // initialization 
int arr[] = {1, 2, 3, 4, 5}; // The standard dictates that the size of the array
                             // be given by the amount of members in the initializer  
arr = { 1, 2, 3, 4, 5 }; // ERROR

অন্যদিকে, আপনি পয়েন্টারগুলির সাথে যা কিছু করতে চান তা করতে পারেন। দুর্ভাগ্যক্রমে, যেহেতু পয়েন্টার এবং অ্যারেগুলির মধ্যে পার্থক্যটি জাভা এবং সি # তে হাতে-ওয়েভ করা হয়েছে, আর নতুনরা পার্থক্য বুঝতে পারে না।

৩. পলিমারফিজম

জাভা এবং সি # এর সুবিধাগুলি রয়েছে যা আপনাকে বস্তুটিকে অন্য হিসাবে বিবেচনা করার অনুমতি দেয়, উদাহরণস্বরূপ asকীওয়ার্ডটি ব্যবহার করে । সুতরাং যদি কেউ কোনও Entityঅবজেক্টকে একটি অবজেক্ট হিসাবে বিবেচনা Playerকরতে চায় তবে Player player = Entity as Player;এটি করতে পারে আপনি যদি একটি একজাতীয় ধারকটিতে ফাংশন কল করতে চান যা কেবলমাত্র একটি নির্দিষ্ট ধরণের ক্ষেত্রে প্রয়োগ করা উচিত। কার্যকারিতা নীচে অনুরূপ ফ্যাশনে অর্জন করা যেতে পারে:

std::vector<Base*> vector;
vector.push_back(&square);
vector.push_back(&triangle);
for (auto& e : vector)
{
     auto test = dynamic_cast<Triangle*>(e); // I only care about triangles
     if (!test) // not a triangle
        e.GenericFunction();
     else
        e.TriangleOnlyMagic();
}

সুতরাং বলুন যে কেবল ত্রিভুজগুলির কোনও ঘোরানো ফাংশন থাকলে, আপনি এটি ক্লাসের সমস্ত অবজেক্টে কল করার চেষ্টা করলে এটি সংকলক ত্রুটি হবে। ব্যবহার করে dynamic_castআপনি asকীওয়ার্ড অনুকরণ করতে পারেন । পরিষ্কার হওয়ার জন্য, যদি কোনও কাস্ট ব্যর্থ হয়, তবে এটি একটি অবৈধ পয়েন্টার দেয়। সুতরাং !testমূলত testNUL বা একটি অবৈধ পয়েন্টার কিনা তা যাচাই করার জন্য একটি শর্টহ্যান্ড হ'ল যার অর্থ কাস্ট ব্যর্থ হয়েছে।

স্বয়ংক্রিয় ভেরিয়েবলের সুবিধা

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

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

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

1. (এন) আরভিও - আক, (নামযুক্ত) রিটার্ন মান অপ্টিমাইজেশন

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

আপনি যদি পয়েন্টার ব্যবহার করেন তবে (এন) আরভিও ঘটে না । আপনি যদি অপ্টিমাইজেশন সম্পর্কে উদ্বিগ্ন হন তবে পয়েন্টারগুলি ফিরে বা পাসের পরিবর্তে (এন) আরভিওর সুবিধা নেওয়া আরও বেশি সুবিধাজনক এবং কম ত্রুটিযুক্ত pr ত্রুটি ফাঁস ঘটতে পারে যদি কোনও ফাংশনের কলার deleteগতিশীল বরাদ্দকৃত বস্তু এবং এই জাতীয় জন্য দায়বদ্ধ থাকে । যদি কোনও গরম আলুর মতো পয়েন্টারগুলি পাশ কাটিয়ে দেওয়া হয় তবে কোনও সামগ্রীর মালিকানা ট্র্যাক করা কঠিন। কেবল স্ট্যাক ভেরিয়েবলগুলি ব্যবহার করুন কারণ এটি সহজ এবং আরও ভাল।


"সুতরাং! পরীক্ষাটি পরীক্ষাটি নুল বা অবৈধ পয়েন্টার, যার অর্থ কাস্ট ব্যর্থ হয়েছে কিনা তা যাচাই করার জন্য মূলত শর্টহ্যান্ড।" আমি মনে করি স্পষ্টতার জন্য এই বাক্যটি অবশ্যই আবার লিখতে হবে।
বার্কাস

4
"জাভা হাইপ মেশিনটি আপনাকে বিশ্বাস করতে চাইবে" - হতে পারে ১৯৯ 1997 সালে, তবে এটি এখন অ্যানাক্রোনিস্টিক, ২০১৪ সালে জাভা সি ++ এর সাথে তুলনা করার আর প্রেরণা নেই।
ম্যাট আর

15
পুরানো প্রশ্ন, তবে কোড সেগমেন্টে { std::string* s = new std::string; } delete s; // destructor called.... অবশ্যই এটি deleteকাজ করবে না কারণ সংকলকটি sআর কি তা জানবে না?
Badger5000

2
আমি -1 দিচ্ছি না, তবে লিখিত হিসাবে খোলার বক্তব্যগুলির সাথে আমি একমত নই। প্রথমে, আমি কোনও "হাইপ" আছে তা নিয়ে একমত নই - ওয়াই 2 কে এর আশেপাশে থাকতে পারে তবে এখন উভয় ভাষাই ভালভাবে বোঝা গেছে। দ্বিতীয়ত, আমি যুক্তি দেব যে তারা একেবারে অনুরূপ - সি ++ সিমুলার সাথে সি বিবাহিত, জাভা ভার্চুয়াল মেশিন যোগ করে, আবর্জনা সংগ্রাহক এবং হ্যাভিলি বৈশিষ্ট্যগুলি হ্রাস করে এবং সি # স্ট্রিমলাইনগুলি এবং জাভাতে হারিয়ে যাওয়া বৈশিষ্ট্যগুলিকে পুনরায় পরিচয় করে। হ্যাঁ, এটি নিদর্শনগুলি এবং বৈধ ব্যবহারকে প্রচুর পৃথক করে তোলে তবে সাধারণ অবকাঠামো / ডিজিংগুলি বোঝা সুবিধাজনক যাতে কেউ পার্থক্যগুলি দেখতে পায় see
গেরাসিমোস আর

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

23

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

জাভা ভান করে যে 'এটিকে কখন এবং কখন ধ্বংস করা উচিত?' বলে কোনও সমস্যা নেই। উত্তরটি: দ্য আবর্জনা সংগ্রাহক, দুর্দান্ত এবং ভয়ঙ্কর। তা সত্ত্বেও, এটি মেমরি তথ্য ফাঁসের বিরুদ্ধে 100% সুরক্ষা প্রদান করতে পারেন না (হ্যাঁ, জাভা পারেন মেমরি লিক )। আসলে, জিসি আপনাকে সুরক্ষার একটি ভুল ধারণা দেয়। আপনার এসইউভিটি যত বড় হবে, সরিয়ে নেওয়ার পথে তত দীর্ঘ।

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

এখনও ভয় পাচ্ছেন না? ঠিক আছে: চক্রীয় রেফারেন্স - এগুলি নিজেই পরিচালনা করুন, মানব। এবং মনে রাখবেন: প্রতিটি বস্তুকে অবশ্যই একবার মেরে ফেলুন, আমরা সি ++ রানটাইম তাদের পছন্দ করি না যারা মৃতদেহের সাথে জগাখিচুড়ি করে, মৃত ব্যক্তিকে একা রেখে দেয়।

সুতরাং, আপনার প্রশ্ন ফিরে।

যখন আপনি নিজের বস্তুকে মূল্য দিয়ে পাঠিয়েছেন, পয়েন্টার বা রেফারেন্সের সাহায্যে নয়, আপনি বস্তুটি অনুলিপি করেন (পুরো বস্তুটি, এটি কয়েকটা বাইট বা বিশাল ডাটাবেস ডাম্প হোক না কেন - আপনি এতক্ষণে স্মার্ট হয়ে যান যে আপনি পরবর্তীতে এড়াতে পারবেন না ' t আপনি?) প্রতিবার আপনি '=' করেন। এবং অবজেক্টের সদস্যদের অ্যাক্সেস করতে, আপনি 'ব্যবহার করুন। (DOT)।

আপনি যখন পয়েন্টার দিয়ে আপনার অবজেক্টটি পাস করবেন, আপনি কেবলমাত্র কয়েকটি বাইট (32-বিট সিস্টেমে 4, 64-বিট সিস্টেমে 8) অনুলিপি করুন - এই বস্তুর ঠিকানা। এবং প্রত্যেককে এটি দেখানোর জন্য, আপনি সদস্যদের অ্যাক্সেস করার সময় আপনি এই অভিনব '->' অপারেটরটি ব্যবহার করেন। অথবা আপনি '*' এবং 'এর সংমিশ্রণটি ব্যবহার করতে পারেন।

আপনি যখন রেফারেন্স ব্যবহার করেন, তারপরে আপনি পয়েন্টারটি পান যা একটি মান বলে ভান করে। এটি একটি পয়েন্টার, তবে আপনি '' এর মাধ্যমে সদস্যদের অ্যাক্সেস করতে পারেন।

এবং, আপনার মনকে আরও একবার ফুটিয়ে তুলতে: আপনি যখন কমা দ্বারা পৃথককৃত বেশ কয়েকটি ভেরিয়েবল ঘোষণা করেন, তখন (হাত দেখুন):

  • টাইপ প্রত্যেককে দেওয়া হয়
  • মান / পয়েন্টার / রেফারেন্স সংশোধক পৃথক

উদাহরণ:

struct MyStruct
{
    int* someIntPointer, someInt; //here comes the surprise
    MyStruct *somePointer;
    MyStruct &someReference;
};

MyStruct s1; //we allocated an object on stack, not in heap

s1.someInt = 1; //someInt is of type 'int', not 'int*' - value/pointer modifier is individual
s1.someIntPointer = &s1.someInt;
*s1.someIntPointer = 2; //now s1.someInt has value '2'
s1.somePointer = &s1;
s1.someReference = s1; //note there is no '&' operator: reference tries to look like value
s1.somePointer->someInt = 3; //now s1.someInt has value '3'
*(s1.somePointer).someInt = 3; //same as above line
*s1.somePointer->someIntPointer = 4; //now s1.someInt has value '4'

s1.someReference.someInt = 5; //now s1.someInt has value '5'
                              //although someReference is not value, it's members are accessed through '.'

MyStruct s2 = s1; //'NO WAY' the compiler will say. Go define your '=' operator and come back.

//OK, assume we have '=' defined in MyStruct

s2.someInt = 0; //s2.someInt == 0, but s1.someInt is still 5 - it's two completely different objects, not the references to the same one

1
std::auto_ptrঅবচয় করা হয়েছে, দয়া করে এটি ব্যবহার করবেন না।
নীল

2
খুব নিশ্চিত যে আপনি সূচনা ভেরিয়েবল অন্তর্ভুক্ত একটি সূচনা তালিকা সহ কোনও কনস্ট্রাক্টর সরবরাহ না করেই সদস্য হিসাবে কোনও রেফারেন্স রাখতে পারবেন না। (তাত্ক্ষণিকভাবে একটি রেফারেন্স শুরু করতে হবে
ruct এমনকি কনস্ট্রাক্টর বডিও

20

সি ++ এ, স্ট্যাকের জন্য বরাদ্দকৃত অবজেক্টগুলি ( Object object;একটি ব্লকের মধ্যে বিবৃতি ব্যবহার করে ) কেবলমাত্র তাদের ঘোষিত ক্ষেত্রের মধ্যেই বেঁচে থাকবে code যখন কোডের ব্লকটি কার্যকরকরণ শেষ করে, ঘোষিত বস্তুটি ধ্বংস হয়ে যায়। আপনি যদি গাদাতে ব্যবহার করে মেমরি বরাদ্দ করেন তবে Object* obj = new Object(), তারা কল না করা পর্যন্ত তারা স্তূপে বাস করে delete obj

আমি হিপগুলিতে একটি অবজেক্ট তৈরি করব যখন আমি কেবলমাত্র কোডের ব্লকটিতে ঘোষিত / বরাদ্দকৃত জিনিসটি ব্যবহার করতে চাই না।


6
Object objসর্বদা স্ট্যাকের উপরে থাকে না - উদাহরণস্বরূপ গ্লোবাল বা সদস্য ভেরিয়েবল।
টেনফোর

2
টুইট কথাটি এটি পরিষ্কার ছিল না, এখন এটি সংশোধন করেছেন - উত্তরে "একটি ব্লকের মধ্যে" যুক্ত করুন। আশা করি এখন এটির মিথ্যা তথ্য নয় :)
কার্তিক কল্যাণসুন্দরাম

20

তবে আমি বুঝতে পারি না কেন আমাদের এটি এ জাতীয় ব্যবহার করা উচিত?

আপনি যদি ব্যবহার করেন তবে ফাংশন বডিটির ভিতরে এটি কীভাবে কাজ করে তা আমি তুলনা করব:

Object myObject;

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

যদি আপনি ফাংশন বডি ভিতরে লিখেন:

 Object *myObject = new Object;

তারপরে অবজেক্ট ক্লাস উদাহরণটি নির্দেশিত myObjectফাংশনটি একবারে শেষ হয়ে যাবে এবং বরাদ্দ হ'ল।

এখন আপনি যদি জাভা প্রোগ্রামার হন তবে দ্বিতীয় উদাহরণটি জাভাটির অধীনে কীভাবে অবজেক্ট বরাদ্দ কাজ করে তার কাছাকাছি। এই লাইন: Object *myObject = new Object;জাভা সমতূল্য: Object myObject = new Object();। পার্থক্যটি হ'ল জাভা মাইওবজেক্টের অধীনে ময়লা আবর্জনা সংগ্রহ করা হবে, যখন সি ++ এর অধীনে এটি মুক্তি পাবে না, আপনি অবশ্যই কোথাও স্পষ্টভাবে কল করুন; মাইঅবজেক্টটি মুছুন; ' অন্যথায় আপনি মেমরি ফাঁস প্রবর্তন করবে।

যেহেতু সি ++ ১১ আপনি গতিশীল বরাদ্দের নিরাপদ উপায়গুলি ব্যবহার করতে পারেন new Object:, শেয়ার্ড_পিটিআর / অনন্য_প্ট্রে মান সংরক্ষণ করে।

std::shared_ptr<std::string> safe_str = make_shared<std::string>("make_shared");

// since c++14
std::unique_ptr<std::string> safe_str = make_unique<std::string>("make_shared"); 

এছাড়াও, অবজেক্টগুলি প্রায়শই পাত্রে সংরক্ষণ করা হয়, যেমন ম্যাপ-এস বা ভেক্টর-এস, তারা স্বয়ংক্রিয়ভাবে আপনার সামগ্রীর আজীবন পরিচালনা করবে।


1
then myObject will not get destroyed once function endsএটা একেবারে হবে।
অরবিট

6
পয়েন্টার ক্ষেত্রে, myObjectএখনও অন্য স্থানীয় পরিবর্তনশীল যেমন ইচ্ছা, ধ্বংস করা হবে। পার্থক্যটি হ'ল এর মানটি কোনও বস্তুর কাছে পয়েন্টার হয় না, বস্তু নিজেই হয় না এবং বোবা পয়েন্টারের ধ্বংস তার পয়েন্টটিকে প্রভাবিত করে না। সুতরাং অবজেক্ট বলে বেঁচে থাকবে ধ্বংস।
সিএওও

স্থির করা হয়েছে যে, স্থানীয় ভেরিয়েবলগুলি (এতে পয়েন্টার অন্তর্ভুক্ত) অবশ্যই মুক্তি দেওয়া হবে - তারা স্ট্যাকের মধ্যে রয়েছে।
marcinj

13

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

এগুলি ছাড়া আপনার বুঝতে হবে যে "নতুন" কোনও সময়ে মুক্ত হওয়া দরকার সেই স্তূপে মেমরির বরাদ্দ করে। যখন আপনাকে "নতুন" ব্যবহার করতে হবে না আমি আপনাকে পরামর্শ দিচ্ছি যে আপনি স্ট্যাকের উপর "নিয়মিত অবজেক্ট সংজ্ঞা" ব্যবহার করুন "।


6

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

আপনি আপনার প্রশ্নে আরও একটি বিষয় উল্লেখ করেছেন:

Object *myObject = new Object;

এটা কিভাবে কাজ করে? এটি টাইপটির পয়েন্টার তৈরি করে Object, একটি বস্তুর ফিট করার জন্য মেমরি বরাদ্দ করে এবং ডিফল্ট কনস্ট্রাক্টরকে কল করে, ভাল লাগে, তাই না? তবে আসলে এটি এতটা ভাল নয়, আপনি যদি গতিশীলভাবে মেমরি বরাদ্দ করেন (ব্যবহৃত কীওয়ার্ড new), আপনাকে ম্যানুয়ালি ম্যানুয়ালি মুক্ত করতে হবে, তার মানে কোডটিতে আপনার হওয়া উচিত:

delete myObject;

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


এবং এখন কিছু ভূমিকা শেষ হয়েছে এবং আবার প্রশ্নে ফিরে যান।

ফাংশনের মধ্যে ডেটা স্থানান্তর করার সময় ভাল পারফরম্যান্স পেতে আপনি বস্তুর পরিবর্তে পয়েন্টার ব্যবহার করতে পারেন।

একবার দেখুন, আপনার কাছে std::string(এটিও আপত্তিজনক) রয়েছে এবং এটিতে সত্যিকার অর্থে প্রচুর ডেটা রয়েছে, উদাহরণস্বরূপ বড় এক্সএমএল, এখন আপনাকে এটি বিশ্লেষণ করতে হবে, তবে তার জন্য আপনার কার্য রয়েছে void foo(...)যা বিভিন্ন উপায়ে ঘোষণা করা যেতে পারে:

  1. void foo(std::string xml); এই ক্ষেত্রে আপনি আপনার পরিবর্তনশীল থেকে স্ট্যাক ফাংশনে সমস্ত ডেটা অনুলিপি করবেন, এতে কিছুটা সময় লাগে, সুতরাং আপনার কার্য সম্পাদন কম হবে।
  2. void foo(std::string* xml); এক্ষেত্রে আপনি পয়েন্টারকে অবজেক্টে পাস করবেন, একই গতিটি পাস করার মতো size_tচলক হিসাবে চলবে , তবে এই ঘোষণায় ত্রুটির প্রবণতা রয়েছে, কারণ আপনি NULLপয়েন্টার বা অবৈধ পয়েন্টারটি পাস করতে পারেন । পয়েন্টারগুলি সাধারণত ব্যবহৃত হয় Cকারণ এর উল্লেখ নেই।
  3. void foo(std::string& xml); এখানে আপনি রেফারেন্সটি পাস করেন, মূলত এটি পাসিং পয়েন্টার হিসাবে সমান, তবে সংকলক কিছু স্টাফ করে এবং আপনি অবৈধ রেফারেন্সটি পাস করতে পারবেন না (অবৈধ রেফারেন্সের সাথে পরিস্থিতি তৈরি করা সম্ভব, তবে এটি সংকলককে ট্রিকিং করছে)।
  4. void foo(const std::string* xml); এখানে দ্বিতীয় হিসাবে একই, ঠিক পয়েন্টার মান পরিবর্তন করা যায় না।
  5. void foo(const std::string& xml); এখানে তৃতীয় হিসাবে একই, কিন্তু বস্তুর মান পরিবর্তন করা যায় না।

আমি কী আরও উল্লেখ করতে চাই, আপনি কোন 5 টি বরাদ্দ উপায় বেছে নিয়েছেন তা নির্ধারণ না করে (সাথে newবা নিয়মিত ) ডেটা পাস করার জন্য আপনি এই 5 টি উপায় ব্যবহার করতে পারেন ।


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


5

আসুন বলে রাখুন যে আপনার কাছে class Aএটি রয়েছে class Bযখন আপনি class Bবাইরের কোনও ফাংশনটি কল করতে চান তখন class Aকেবল এই শ্রেণীর কাছে একটি পয়েন্টার পাবেন এবং আপনি যা চান তা করতে পারেন এবং এটি class Bআপনার প্রসঙ্গেও পরিবর্তন ঘটবেclass A

তবে ডায়নামিক অবজেক্টে সাবধান থাকুন


5

পয়েন্টারগুলিকে আপত্তি করার জন্য ব্যবহার করার অনেক সুবিধা রয়েছে -

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

3

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


3
Object *myObject = new Object;

এটি করার ফলে কোনও অবজেক্টের (হিপে থাকা) একটি রেফারেন্স তৈরি হবে যা মেমরি ফাঁস এড়াতে স্পষ্টভাবে মুছতে হবে ।

Object myObject;

এটি করার ফলে স্বয়ংক্রিয় ধরণের (স্ট্যাকের) একটি অবজেক্ট (মাইবজেক্ট) তৈরি হবে যা বস্তুটি (মাইবজেক্ট) সুযোগের বাইরে চলে গেলে স্বয়ংক্রিয়ভাবে মুছে ফেলা হবে।


1

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

আপনার প্রশ্নের উত্তর দিতে, এটি কেবল আপনার পছন্দ। আমি জাভা-এর মতো সিনট্যাক্স ব্যবহার করতে পছন্দ করি।


হ্যাশ টেবিল? কিছু জেভিএম হতে পারে তবে এটিতে বিশ্বাস রাখবেন না।
ঝ্যান লিংস

জাভা নিয়ে আসা জেভিএম সম্পর্কে কী? অবশ্যই আপনি যে কোনও বাস্তবায়ন করতে পারেন আপনি এমন কোনও JVM এর মতো ভাবতে পারেন যা সরাসরি পয়েন্টার ব্যবহার করে বা এমন পদ্ধতি যা পয়েন্টার গণিত করে। এটি "সাধারণ সর্দিতে মানুষ মারা যায় না" বলে এবং প্রতিক্রিয়া পাওয়ার মতো "সম্ভবত বেশিরভাগ লোক তা বিশ্বাস করে না তবে!" হা হা।
রিওরিকোরিক

2
@ রিওরিকো রিক হটস্পট জাভা রেফারেন্সগুলিকে স্থানীয় পয়েন্টার হিসাবে প্রয়োগ করে, ডকস.অরাকল.com/ জাভাসে / / / ডকস / টেকনোটস / গাইডস / ভিএম/… দেখুন যতদুর আমি দেখতে পারেন, JRockit একই আছে। তারা উভয়ই ওওপি সংক্ষেপণ সমর্থন করে তবে কখনও হ্যাশ-টেবিল ব্যবহার করে না। পারফরম্যান্স পরিণতি সম্ভবত বিপর্যয়কর হবে। এছাড়াও, "এটি কেবল আপনার পছন্দ" বোঝাচ্ছে যে দু'টিই সমতুল্য আচরণের জন্য কেবল ভিন্ন বাক্য গঠন যা অবশ্যই তা নয়।
সর্বোচ্চ ব্যারাক্লফ


0

পয়েন্টার সহ ,

  • সরাসরি স্মৃতিতে কথা বলতে পারে।

  • পয়েন্টারগুলি ম্যানিপুলেট করে কোনও প্রোগ্রামের প্রচুর মেমরি ফাঁস রোধ করতে পারে।


4
" সি ++ তে, পয়েন্টার ব্যবহার করে, আপনি আপনার নিজের প্রোগ্রামের জন্য একটি কাস্টম আবর্জনা সংগ্রহকারী তৈরি করতে পারেন " যা ভয়ানক ধারণা বলে মনে হচ্ছে।
কোয়ান্ট

0

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


0

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


0

আমি পয়েন্টারের একটি গুরুত্বপূর্ণ ব্যবহারের কেস অন্তর্ভুক্ত করব। আপনি যখন বেস ক্লাসে কিছু বস্তুর সঞ্চয় করছেন তবে এটি বহুকোষী হতে পারে।

Class Base1 {
};

Class Derived1 : public Base1 {
};


Class Base2 {
  Base *bObj;
  virtual void createMemerObects() = 0;
};

Class Derived2 {
  virtual void createMemerObects() {
    bObj = new Derived1();
  }
};

সুতরাং এই ক্ষেত্রে আপনি bObj কে সরাসরি অবজেক্ট হিসাবে ঘোষণা করতে পারবেন না, আপনার পয়েন্টার থাকতে হবে।


-5

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


14
আপনার রেফারেন্স দিয়ে পাস করা পছন্দ করা উচিত
বলভ

2
আমি পরিবর্তনশীল জন্য নির্দিষ্ট-রেফারেন্স দ্বারা ক্ষণস্থায়ী সুপারিশ std::string test;আমরা আছে void func(const std::string &) {}কিন্তু যদি না ফাংশন ইনপুট যে ক্ষেত্রে আমি পয়েন্টার ব্যবহার করার প্রস্তাব পরিবর্তন প্রয়োজন (তাই যে কেউ কোড পড়া নোটিশ দেয় &, এবং ফাংশন বুঝতে পারে তার ইনপুট পরিবর্তন করতে পারেন)
Top- মাস্টার

-7

ইতিমধ্যে অনেক দুর্দান্ত উত্তর রয়েছে তবে আমি আপনাকে একটি উদাহরণ দিই:

আমার একটি সাধারণ আইটেম ক্লাস রয়েছে:

 class Item
    {
    public: 
      std::string name;
      int weight;
      int price;
    };

আমি তাদের একটি গুচ্ছ রাখা একটি ভেক্টর তৈরি।

std::vector<Item> inventory;

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

std::vector<Item *> inventory;

... এবং নতুন মাধ্যমে আমার মিলিয়ন আইটেম অবজেক্ট তৈরি করুন। আমি আমার কোডে কেবলমাত্র পরিবর্তনগুলি হ'ল আইটেমগুলিতে পয়েন্টারগুলি ব্যবহার করা, শেষে আমি স্মৃতি পরিষ্কার করার জন্য একটি লুপ যুক্ত করি। এই প্রোগ্রামটি 40 সেকেন্ডের চেয়ে কম বা 10x গতিবেগের চেয়ে বেশি উন্নত হয়। সম্পাদনা: কোডটি http://pastebin.com/DK24SPeW এ রয়েছে সংকলক অপ্টিমাইজেশনের সাহায্যে এটি কেবলমাত্র মেশিনটিতে পরীক্ষা করেছি এমন মেশিনে কেবলমাত্র 3.4x বৃদ্ধি দেখায় যা এখনও যথেষ্ট বিবেচ্য।


2
আচ্ছা আপনি কি তবে পয়েন্টারগুলির সাথে তুলনা করছেন বা আপনি এখনও প্রকৃত বস্তুর তুলনা করছেন? আমি খুব সন্দেহ করি যে অন্য একটি স্তর নির্দেশনা কার্য সম্পাদন করতে পারে। কোড সরবরাহ করুন! আপনি পরে সঠিকভাবে পরিষ্কার?
স্টেফান

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

2
এখানে কোড আপনার উদাহরণের জন্য কার্যত কোনও পার্থক্য দেখাচ্ছে: বাছাই করা। পয়েন্টার কোডটি কেবলমাত্র বাছাইয়ের জন্য অ-পয়েন্টার কোডের চেয়ে 6% দ্রুত, তবে সামগ্রিকভাবে এটি পয়েন্টারবিহীন কোডের চেয়ে 10% ধীর। ideone.com/G0c7zw
স্টিফান

3
কি ওয়ার্ড: push_back। অবশ্যই এই কপি। emplaceআপনার অবজেক্ট তৈরি করার সময় আপনার জায়গায় থাকা উচিত ছিল (যদি না আপনি অন্য কোথাও ক্যাশে যাওয়ার প্রয়োজন না হয়)।
আন্ডারস্কোর_ডি

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