আমি আমার জীবনের মাত্র তিন দিন হারিয়েছি খুব অদ্ভুত একটি বাগটি অনুসরণ করতে যেখানে আনর্ডার্ড_ম্যাপ :: সন্নিবেশ () আপনার সন্নিবেশ করা চলকটি ধ্বংস করে। এই অতি-স্পষ্ট আচরণটি কেবলমাত্র সাম্প্রতিক সংকলকগুলিতেই ঘটে: আমি দেখতে পেয়েছি যে ঝাঁকুনি ৩.২-৩.৪ এবং জিসিসি ৪.৮ এই "বৈশিষ্ট্য" প্রদর্শনের একমাত্র সংকলক।
এখানে আমার প্রধান কোড বেস থেকে কিছু হ্রাসকৃত কোড যা সমস্যাটি দেখায়:
#include <memory>
#include <unordered_map>
#include <iostream>
int main(void)
{
std::unordered_map<int, std::shared_ptr<int>> map;
auto a(std::make_pair(5, std::make_shared<int>(5)));
std::cout << "a.second is " << a.second.get() << std::endl;
map.insert(a); // Note we are NOT doing insert(std::move(a))
std::cout << "a.second is now " << a.second.get() << std::endl;
return 0;
}
আমি সম্ভবত বেশিরভাগ সি ++ প্রোগ্রামারদের মতো আউটপুটটিকেও এরকম কিছু দেখতে প্রত্যাশা করব:
a.second is 0x8c14048
a.second is now 0x8c14048
তবে ঝাঁকুনি দিয়ে 3.2-3.4 এবং জিসিসি 4.8 দিয়ে আমি এটি পরিবর্তে পেয়েছি:
a.second is 0xe03088
a.second is now 0
আপনি অর্ডারড_ম্যাপ :: সন্নিবেশ () এর জন্য দস্তাবেজগুলি http://www.cplsplus.com/references/unordered_map/unordered_map/insert/ এ পরীক্ষা না করা অবধি কোনও অর্থ হতে পারে যেখানে ওভারলোড নং 2 হবেন:
template <class P> pair<iterator,bool> insert ( P&& val );
যা লোভী সার্বজনীন রেফারেন্স মুভ ওভারলোড, অন্য কোনও ওভারলোডের সাথে কোনওরকম নয় এমন কিছু গ্রহণ করে এবং consum নির্মাণের সরাতে একটি VALUE_TYPE সেটিকে। তাহলে কেন আমাদের উপরের কোডগুলি এই ওভারলোডটি বেছে নিয়েছে, এবং আনর্ডার্ড_ম্যাপ :: মান_প্রকারের ওভারলোডকে সম্ভবত সম্ভবত প্রত্যাশা করবে না?
উত্তর মুখে তাকিয়ে: unordered_map :: VALUE_TYPE একজোড়া হল < const কোন int, এসটিডি :: shared_ptr> এবং কম্পাইলার সঠিকভাবে যে একজোড়া <মনে হবে int- এ , এসটিডি :: shared_ptr> পরিবর্তনীয় নয়। অতএব কম্পাইলার পদক্ষেপ সার্বজনীন রেফারেন্স জমিদার চয়ন করে এবং আসল নষ্ট করে সত্ত্বেও প্রোগ্রামার ব্যবহার করছেন না এসটিডি :: পদক্ষেপ () যা ইঙ্গিত আপনি যদি একটি পরিবর্তনশীল ধ্বংস পেয়ে সঙ্গে ঠিক আছ জন্য আদর্শ কনভেনশন হয়। সুতরাং সন্নিবেশ বিনষ্টকারী আচরণটি সি ++ 11 স্ট্যান্ডার্ড অনুযায়ী আসলে সঠিক এবং পুরানো সংকলকগুলি ছিল ভুল ।
আপনি সম্ভবত দেখতে পাবেন যে এই ত্রুটিটি সনাক্ত করতে আমি কেন তিন দিন সময় নিলাম। এটি কোনও বৃহত কোড বেসে একেবারেই স্পষ্ট ছিল না যেখানে আনর্ডারড_ম্যাপে টাইপটি টাইপডেফটি সোর্স কোডের পদে অনেক দূরে সংজ্ঞায়িত করা হয়েছিল, এবং টাইপডেফটি মান_প্রকারের মতো কিনা তা পরীক্ষা করার জন্য কারওর কাছে কখনও ঘটেনি।
সুতরাং স্ট্যাক ওভারফ্লোতে আমার প্রশ্নগুলি:
পুরানো সংকলকরা কেন নতুন সংকলকগুলির মতো variোকানো ভেরিয়েবলগুলি ধ্বংস করে না? আমি বলতে চাইছি, এমনকি জিসিসি 4.7 এটিও করে না এবং এটি বেশ মানক।
এই সমস্যাটি কি বহুল পরিচিত, কারণ অবশ্যই সংকলনকারীদের আপগ্রেড করা এমন কোডের কারণ হয়ে যাবে যা হঠাৎ কাজ বন্ধ করার জন্য কাজ করত?
সি ++ স্ট্যান্ডার্ড কমিটি কি এই আচরণের পরিকল্পনা করেছিল?
আপনি কীভাবে পরামর্শ দিবেন যে আনর্ডার্ড_ম্যাপ :: সন্নিবেশ () আরও ভাল আচরণের জন্য সংশোধন করা হবে? আমি এটি জিজ্ঞাসা করছি কারণ যদি এখানে সমর্থন থাকে তবে আমি এই আচরণটিকে ডাব্লুজি 21-র কাছে একটি নোট হিসাবে জমা দেওয়ার এবং তাদের আরও ভাল আচরণ বাস্তবায়নের অনুরোধ করছি।
4.9.0 20131223 (experimental)
যথাক্রমে জিসিসি ৪.৮.২ ব্যবহার করছি । আউটপুট আমার জন্য a.second is now 0x2074088
(বা অনুরূপ)।
a
নয়। এটি একটি অনুলিপি করা উচিত। এছাড়াও, এই আচরণটি সম্পূর্ণরূপে stdlib উপর নির্ভর করে, সংকলক নয়।