ধরুন আমার কাছে নিম্নলিখিত কোড রয়েছে:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
এটি কি নিরাপদ? বা মুছে ফেলার আগে ptrকাস্ট করা উচিত char*?
ধরুন আমার কাছে নিম্নলিখিত কোড রয়েছে:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
এটি কি নিরাপদ? বা মুছে ফেলার আগে ptrকাস্ট করা উচিত char*?
উত্তর:
এটি "নিরাপদ" উপর নির্ভর করে। এটি সাধারণত কাজ করবে কারণ বরাদ্দটি সম্পর্কে পয়েন্টারের পাশাপাশি তথ্য সংরক্ষণ করা হয়, তাই ডেলোকোটার এটিকে সঠিক জায়গায় ফিরিয়ে দিতে পারে। এই অর্থে এটি "নিরাপদ" যতক্ষণ না আপনার বরাদ্দকারী অভ্যন্তরীণ সীমানা ট্যাগগুলি ব্যবহার করে। (অনেকেই করেন।)
তবে অন্যান্য উত্তরে যেমন উল্লেখ করা হয়েছে, শূন্য পয়েন্টার মোছা ধ্বংসকারীদের কল করবে না, যা সমস্যা হতে পারে। সেই অর্থে এটি "নিরাপদ" নয়।
আপনি যেভাবে করছেন তা করার কোনও ভাল কারণ নেই। আপনি যদি নিজের নিজস্ব deallocation ফাংশন লিখতে চান তবে আপনি সঠিক ধরণের সাথে ফাংশন তৈরি করতে ফাংশন টেম্পলেট ব্যবহার করতে পারেন। এটি করার একটি ভাল কারণ হ'ল পুল বরাদ্দকারী উত্পাদন করা, যা নির্দিষ্ট ধরণের জন্য অত্যন্ত দক্ষ হতে পারে।
অন্যান্য উত্তরে যেমন উল্লেখ করা হয়েছে, এটি সি ++ তে অনির্ধারিত আচরণ । সাধারণভাবে অপরিজ্ঞাত আচরণ এড়ানো ভাল, যদিও বিষয়টি নিজেই জটিল এবং বিরোধী মতামত দ্বারা ভরা।
sizeof(T*) == sizeof(U*)সকলের জন্য T,Uপরামর্শ দেয় যে এটি 1 টি নন টেম্পলেটযুক্ত, void *ভিত্তিক আবর্জনা সংগ্রহকারী বাস্তবায়ন করা উচিত। তবে তারপরে, যখন জিসিটি আসলে একটি পয়েন্টার মুছতে / মুক্ত করতে হয় ঠিক এই প্রশ্নটি দেখা দেয়। এটি কার্যকর করার জন্য, আপনাকে হয় ল্যাম্বডা ফাংশন ডেস্ট্রাক্টর র্যাপারগুলি (উরগ) দরকার হয় অথবা আপনার কোনও ধরণের গতিশীল "টাইপ হিসাবে ডেটা" ধরণের জিনিস প্রয়োজন যা কোনও ধরণের এবং স্ট্যাটিভ কিছুতে পিছনে পিছনে অনুমতি দেয়।
একটি অকার্যকর পয়েন্টারটির মাধ্যমে মুছে ফেলা সি ++ স্ট্যান্ডার্ড দ্বারা নির্ধারিত - বিভাগ 5.3.5 / 3 দেখুন:
প্রথম বিকল্পে (অবজেক্ট মুছুন), অপারেন্ডের স্থিতিশীল প্রকারটি যদি তার গতিশীল ধরণের থেকে পৃথক হয়, স্থির ধরণটি অপারেন্ডের গতিশীল ধরণের একটি বেস শ্রেণি এবং স্ট্যাটিক ধরণের ভার্চুয়াল ডেস্ট্রাক্টর থাকবে বা আচরণটি অপরিবর্তিত । দ্বিতীয় বিকল্পে (অ্যারে মুছুন) মুছে ফেলা বস্তুর গতিশীল ধরণের যদি তার স্থিতিশীল প্রকারের থেকে পৃথক হয়, তবে আচরণটি অপরিবর্তিত।
এবং এর পাদটীকা:
এর দ্বারা বোঝা যায় যে শূন্য * প্রকারের পয়েন্টার ব্যবহার করে কোনও বস্তু মোছা যায় না কারণ টাইপ শূন্যের কোনও অবজেক্ট নেই
।
NULLঅ্যাপ্লিকেশন মেমরি পরিচালনার জন্য কোনও পার্থক্যের সাথে একটি শূন্য পয়েন্টারের নির্দেশিত ঠিকানা মেমরিটি পূরণ করুন ?
এটি একটি ভাল ধারণা নয় এবং আপনি সি ++ এ যা কিছু করবেন তা নয়। আপনি বিনা কারণে আপনার প্রকারের তথ্য হারাচ্ছেন।
আপনার অ্যারেতে থাকা অবজেক্টগুলিতে আপনার ডেস্ট্রাক্টরকে ডাকা হবে না যা আপনি মুদ্রণ করছেন যখন আপনি অ-আদিম ধরণের জন্য কল করেন।
পরিবর্তে আপনার নতুন / মুছে ফেলা উচিত।
অকার্যকর * মুছে ফেলা সম্ভবত আপনার স্মৃতি যথাযথভাবে মুক্ত করবে, তবে এটি ভুল কারণ ফলাফল অপরিজ্ঞাত।
যদি কোনও কারণে আমার অজানা কারণে আপনার পয়েন্টারটি শূন্যে * সংরক্ষণ করতে হয় তবে এটি মুক্ত করুন, আপনার উচিত ম্যালোক এবং বিনামূল্যে।
প্রশ্নটির কোনও মানে হয় না। আপনার বিভ্রান্তি আংশিকভাবে লোকেদের সাথে প্রায়শই ব্যবহার করা মলা ভাষার কারণে হতে পারেdelete :
আপনি গৌণিকভাবে বরাদ্দ হওয়া deleteকোনও বস্তুটিকে ধ্বংস করতে ব্যবহার করেন । এটি করুন, আপনি সেই অবজেক্টের পয়েন্টার সহ একটি মোছা ভাবটি তৈরি করেন । আপনি কখনই "পয়েন্টার মুছবেন না"। আপনি যা করেন তা হ'ল "এমন কোনও বস্তু মুছুন যা তার ঠিকানা দ্বারা চিহ্নিত হয়"।
এখন আমরা দেখতে পাচ্ছি কেন প্রশ্নটি কোনও অর্থবোধ করে না: শূন্য পয়েন্টারটি "কোনও বস্তুর ঠিকানা" নয়। এটি কেবল কোনও ঠিকানা, কোনও শব্দার্থবিজ্ঞান ছাড়াই। এটা তোলে পারে প্রকৃত বস্তুর ঠিকানা থেকে এসেছি, কিন্তু যে তথ্য, হারিয়ে গেছে, কারণ এটি মধ্যে এনকোড করা হয়েছে টাইপ মূল পয়েন্টার। কোনও অবজেক্ট পয়েন্টারটি পুনরুদ্ধার করার একমাত্র উপায় হ'ল শূন্য পয়েন্টারটিকে কোনও অবজেক্ট পয়েন্টারটিতে ফিরে যেতে (যার জন্য লেখকের পয়েন্টারটির অর্থ কী তা জানতে হবে)। voidনিজেই একটি অসম্পূর্ণ প্রকার এবং এভাবে কোনও বস্তুর ধরণ কখনও হয় না এবং কোনও শূন্য পয়েন্টার কখনই কোনও জিনিস সনাক্ত করতে ব্যবহার করা যায় না। (অবজেক্টগুলি তাদের ধরণ এবং তাদের ঠিকানা দ্বারা যৌথভাবে চিহ্নিত করা হয়))
deleteমানটি একটি নাল পয়েন্টার মান হতে পারে, কোনও নতুন-এক্সপ্রেশন দ্বারা নির্মিত নন-অ্যারে অবজেক্টের জন্য পয়েন্টার বা কোনও পয়েন্টার হতে পারে সাবওজেক্ট যেমন কোনও অবজেক্টের বেস শ্রেণি উপস্থাপন করে। যদি তা না হয় তবে আচরণটি সংজ্ঞায়িত। " সুতরাং কোনও সংকলক যদি ডায়াগনস্টিক ছাড়াই আপনার কোড গ্রহণ করে, এটি
delete void_pointer। এটি অপরিবর্তিত আচরণ। প্রোগ্রামাররা যা করতে চেয়েছিল তাতে যদি প্রতিক্রিয়া উপস্থিত হয় তবে প্রোগ্রামারদের কখনই অপরিজ্ঞাত আচরণ করা উচিত নয়।
আপনি যদি সত্যিই এটি করতেই চান তবে কেন মাঝারি মানুষটিকে ( newএবং deleteঅপারেটরদের) কেটে বের করে বিশ্বব্যাপী operator newএবং operator deleteসরাসরি কল করবেন না ? (অবশ্যই, আপনি উপকরণ করার চেষ্টা করছেন যদি newএবং deleteঅপারেটরদের, আপনি আসলে reimplement কর্তব্য operator newএবং operator delete।)
void* my_alloc (size_t size)
{
return ::operator new(size);
}
void my_free (void* ptr)
{
::operator delete(ptr);
}
মনে রাখবেন যে বিপরীতে malloc(), ব্যর্থতা operator newছোঁড়ে std::bad_alloc(বা new_handlerযদি এটি নিবন্ধিত থাকে তবে কল করে )।
কারণ চরের কোনও বিশেষ ধ্বংসকারী যুক্তি নেই। এই কাজ করবে না।
class foo
{
~foo() { printf("huzza"); }
}
main()
{
foo * myFoo = new foo();
delete ((void*)foo);
}
ডি'ક્ટર কল হবে না।
আপনি যদি শূন্য * ব্যবহার করতে চান তবে আপনি কেবল ম্যালোক / ফ্রি ব্যবহার করবেন না কেন? নতুন / মোছা মেমরি পরিচালনার চেয়ে আরও বেশি কিছু। মূলত, নতুন / মুছে ফেলা কোনও কনস্ট্রাক্টর / ডেস্ট্রাক্টরকে কল করে এবং আরও অনেক কিছু চলছে। যদি আপনি কেবল অন্তর্নির্মিত প্রকারগুলি (যেমন চর *) ব্যবহার করেন এবং এগুলি শূন্য * এর মাধ্যমে মুছে ফেলেন তবে এটি কার্যকর হবে তবে তবুও এটি প্রস্তাবিত নয়। আপনি যদি অকার্যকর * ব্যবহার করতে চান তবে নীচের লাইনটি ম্যালোক / ফ্রি ব্যবহার করা হবে। অন্যথায়, আপনি আপনার সুবিধার জন্য টেমপ্লেট ফাংশন ব্যবহার করতে পারেন।
template<typename T>
T* my_alloc (size_t size)
{
return new T [size];
}
template<typename T>
void my_free (T* ptr)
{
delete [] ptr;
}
int main(void)
{
char* pChar = my_alloc<char>(10);
my_free(pChar);
}
ইতিমধ্যে অনেক লোক মন্তব্য করেছে যে না, এটি একটি শূন্য পয়েন্টার মোছা নিরাপদ নয়। আমি এটির সাথে একমত, তবে আমি এটিও যুক্ত করতে চেয়েছিলাম যে আপনি যদি সুসংগত বিন্যাস বা অনুরূপ কিছু বরাদ্দ দেওয়ার জন্য শূন্য পয়েন্টার নিয়ে কাজ করছেন তবে newআপনি এটির মাধ্যমে এটি করতে পারেন যাতে আপনি deleteনিরাপদে ব্যবহার করতে পারবেন (সহ, আহেম) , অতিরিক্ত কিছু কাজ)। এটি মেমরি অঞ্চলে একটি অকার্যকর পয়েন্টার বরাদ্দ করে (একটি 'আখড়া' নামে পরিচিত) এবং তারপরে নতুনটিকে পয়েন্টার সরবরাহ করে is C ++ FAQ এ এই বিভাগটি দেখুন । এটি সি ++ তে মেমরি পুলগুলি বাস্তবায়নের জন্য একটি সাধারণ পন্থা।
এটি করার খুব কমই কারণ আছে।
প্রথম সব, আপনি জানেন না যদি টাইপ ডাটা, এবং সমস্ত আপনি কি জানেন যে এটা হয় void*, তাহলে আপনি সত্যিই শুধু একটি typeless যেমন যে ডেটা চিকিত্সা করা উচিত ফোঁটা বাইনারি তথ্য (এর unsigned char*), এবং ব্যবহার malloc/ freeতা মোকাবেলা করার । ওয়েভফর্ম ডেটা এবং এর মতো জিনিসের জন্য কখনও কখনও এটির প্রয়োজন হয়, যেখানে আপনাকে void*সি এপিসে পয়েন্টারগুলি কাছাকাছি যেতে হবে । সেটা ঠিক আছে.
আপনি যদি না ডেটার প্রকারের (অর্থাত এটি একটি ctor / dtor আছে), কিন্তু কোনো কারণে আপনি আপ একটি দিয়ে শেষ void*পয়েন্টার (কারনের জন্য আপনি) তারপর আপনি সত্যিই এটা ফিরে টাইপ কাস্ট করা উচিত আপনি এটা জানি হতে , এবং deleteএটি কল ।
কোড প্রতিবিম্ব এবং অস্পষ্টতার অন্যান্য অংশগুলির জন্য আমি আমার কাঠামোটিতে অকার্যকর *, (ওরফে অজানা প্রকার) ব্যবহার করেছি এবং এখন পর্যন্ত আমার কোনও সংকলক থেকে কোনও ঝামেলা হয়নি (মেমরি ফুটো, অ্যাক্সেস লঙ্ঘন ইত্যাদি)। অপারেশনটি মানক নয় বলে শুধুমাত্র সতর্কতা।
এটি কোনও অজানা (শূন্য *) মুছে ফেলার জন্য পুরোপুরি অর্থপূর্ণ। কেবল নিশ্চিত করুন যে পয়েন্টারটি এই নির্দেশিকাগুলি অনুসরণ করে বা এটি বোধগম্যতা থামাতে পারে:
1) অজানা পয়েন্টারটি অবশ্যই এমন ধরণের দিকে নির্দেশ না করে যা একটি তুচ্ছ ডিকনস্ট্রাক্টর থাকে এবং তাই যখন অজানা পয়েন্টার হিসাবে কাস্ট করা হয় তবে এটি মুছে ফেলা উচিত নয়। এটি অরিজিনাল টাইপের মধ্যে ফেলে দেওয়ার পরে কেবল অজানা পয়েন্টারটিকে মুছুন।
2) উদাহরণটি স্ট্যাক বাউন্ড বা হিপ বাউন্ড মেমোরিতে কোনও অজানা পয়েন্টার হিসাবে উল্লেখ করা হচ্ছে? যদি অজানা পয়েন্টারটি স্ট্যাকের কোনও উদাহরণকে উল্লেখ করে, তবে এটি মুছে ফেলা উচিত নয়!
3) আপনি কি 100% ইতিবাচক অজানা পয়েন্টারটি একটি বৈধ মেমরি অঞ্চল? না, তবে এটি কখনই ক্ষয়ক্ষতি হওয়া উচিত নয়!
সব মিলিয়ে অজানা (শূন্য *) পয়েন্টার টাইপ ব্যবহার করে খুব কম সরাসরি কাজ করা যায়। যাইহোক, অপ্রত্যক্ষভাবে, অকার্যকর * সি ++ বিকাশকারীদের যখন ডেটা অস্পষ্টতার প্রয়োজন হয় তখন তার উপর নির্ভর করা a
আপনি যদি কেবল বাফার চান তবে মেলোক / ফ্রি ব্যবহার করুন। আপনি যদি নতুন / মুছতে ব্যবহার করেন তবে একটি তুচ্ছ র্যাপার শ্রেণি বিবেচনা করুন:
template<int size_ > struct size_buffer {
char data_[ size_];
operator void*() { return (void*)&data_; }
};
typedef sized_buffer<100> OpaqueBuffer; // logical description of your sized buffer
OpaqueBuffer* ptr = new OpaqueBuffer();
delete ptr;
চরের বিশেষ ক্ষেত্রে।
চর একটি অন্তর্নিহিত ধরণের যা একটি বিশেষ ধ্বংসকারী নেই। সুতরাং ফাঁস আর্গুমেন্ট একটি শঙ্কা।
আকার (চর) সাধারণত একটি হয় তাই কোনও প্রান্তিক যুক্তিও নেই। দুর্লভ প্ল্যাটফর্মের ক্ষেত্রে যেখানে আকার (চর) এক নয়, তারা তাদের চরের জন্য পর্যাপ্ত প্রান্তরে মেমরি বরাদ্দ করে। সুতরাং প্রান্তিককরণ আর্গুমেন্ট এছাড়াও একটি গতিযুক্ত।
malloc / ফ্রি এই ক্ষেত্রে দ্রুত হবে। তবে আপনি std :: Bad_alloc বাজেয়াপ্ত করেছেন এবং ম্যালোকের ফলাফল পরীক্ষা করতে হবে। মধ্যবিত্তকে বাইপাস করায় গ্লোবালকে নতুন এবং ডিলিট অপারেটরদের কল করা আরও ভাল হতে পারে।
newআসলে নিক্ষেপের সংজ্ঞায়িত। এটা সত্য নয়। এটি সংকলক এবং সংকলক সুইচ নির্ভর। উদাহরণস্বরূপ MSVC2019 /GX[-] enable C++ EH (same as /EHsc)স্যুইচগুলি দেখুন। এম্বেড থাকা সিস্টেমেও অনেকে সি ++ ব্যতিক্রমগুলির জন্য পারফরম্যান্স ট্যাক্স প্রদান না করা পছন্দ করেন। সুতরাং "তবে আপনি বাজেয়াপ্ত করুন :: খারাপ_মহোক ..." দিয়ে শুরু হওয়া বাক্যটি প্রশ্নবিদ্ধ।