پیش از C++17، کار با std::map و std::unordered_map برای درج یا به‌روزرسانی یک کلید، با چالش‌های متعددی همراه بود. استفاده از عملگر operator[] اگرچه ساده به نظر می‌رسید، اما نیاز به ساخت پیش‌فرض (Default-Constructible) بودن نوع مقدار داشت و در صورت وجود کلید، مقدار را بازنویسی می‌کرد. همچنین روش ترکیبی find و insert اگرچه کار می‌کرد، اما باعث انجام دو جستجوی جداگانه می‌شد که از نظر عملکرد بهینه نبود. متد emplace نیز مشکل خاص خود را داشت: حتی اگر درج به دلیل وجود کلید تکراری شکست می‌خورد، ممکن بود آرگومان‌های ارسال‌شده (به‌ویژه آرگومان‌های راست‌مقدار) از قبل جابه‌جا (move) شده باشند و برنامه‌نویس را در موقعیت نامشخصی قرار دهند.

try_emplace: درج شرطی با حفظ آرگومان‌ها

متد try_emplace که در C++17 به std::map و std::unordered_map اضافه شده است، این مشکل را به‌طور کامل حل می‌کند. این متد تنها در صورتی که کلید معادلی در کانتینر وجود نداشته باشد، اقدام به ساخت مقدار جدید با استفاده از آرگومان‌های داده‌شده می‌کند. مزیت کلیدی آن نسبت به emplace سنتی، تضمین عدم جابه‌جایی (move) آرگومان‌ها در صورت شکست درج است. این ویژگی به‌ویژه برای نوع‌هایی که قابل کپی نیستند اما قابل جابه‌جایی هستند، مانند std::unique_ptr، بسیار حیاتی است و از بروز رفتار تعریف‌نشده جلوگیری می‌کند.

insert_or_assign: درج یا به‌روزرسانی یکپارچه

متد insert_or_assign نیز یکی دیگر از افزوده‌های ارزشمند C++17 است که امکان درج در صورت نبود کلید و به‌روزرسانی در صورت وجود را در یک فراخوانی واحد فراهم می‌کند. برخلاف operator[]، این متد نیازی به ساخت پیش‌فرض نوع مقدار ندارد و در صورت به‌روزرسانی، مقدار جدید را مستقیماً به mapped_type انتساب می‌دهد. خروجی این متد یک std::pair<iterator, bool> است که bool آن نشان می‌دهد که آیا درج انجام شده (true) یا به‌روزرسانی (false). این اطلاعات اضافی، در مقایسه با operator[] که هیچ اطلاعی از موفقیت یا نوع عملیات نمی‌دهد، یک مزیت محسوب می‌شود. همچنین این متد از نظر عملکرد، کارآمدتر از operator[] است زیرا از ساخت یک std::pair موقت صرف‌نظر می‌کند.

راهنمای انتخاب و جمع‌بندی

انتخاب بین try_emplace و insert_or_assign به نیاز شما بستگی دارد. اگر قصد دارید فقط در صورت نبود کلید، یک مقدار جدید با استفاده از آرگومان‌های داده‌شده بسازید، try_emplace انتخاب مناسبی است. اما اگر می‌خواهید هم درج و هم به‌روزرسانی را با یک مقدار از پیش ساخته‌شده انجام دهید، insert_or_assign گزینه‌ی ایده‌آل است. همچنین توجه به این نکته مهم است که پیاده‌سازی‌های مدرن کتابخانه‌ی استاندارد، بهینه‌سازی‌هایی را برای این متدها انجام می‌دهند که از تخصیص‌های حافظه‌ی غیرضروری در زمان درج جلوگیری می‌کنند. استفاده از این دو متد مدرن، کد شما را هم خواناتر و هم کارآمدتر می‌سازد و از بروز بسیاری از خطاهای رایج مرتبط با مدیریت حافظه و چرخه‌ی حیات اشیاء جلوگیری می‌کند.

کلیدواژه ها : std::map insert_or_assign-std::map try_emplace-C++17 map insertion-درج بهینه در map-مقایسه insert و emplace-مزایای try_emplace نسبت به emplace-insert_or_assign vs operator[]-C++17 associative containers-به‌روزرسانی map در C++17-std::unordered_map try_emplace-مدیریت unique_ptr در map-درج شرطی در C++-پرفورمنس map-آموزش try_emplace-آموزش insert_or_assign