در std::map و std::unordered_map، کلید هر عنصر به‌صورت غیرقابل تغییر (const) تعریف شده است تا یکپارچگی ساختار داده حفظ شود. در گذشته، برای تغییر کلید یک عنصر، راهی جز حذف و درج مجدد وجود نداشت . این روش سربار سنگینی داشت، زیرا شامل تخصیص و آزادسازی حافظه، کپی یا جابه‌جایی عنصر و انجام عملیات‌های تعادل‌سازی مجدد (Rebalancing) بود. همچنین در صورت وجود اشاره‌گرها یا مراجع به عنصر، پس از حذف، نامعتبر می‌شدند.

راه‌حل مدرن: متد extract

C++17 با معرفی متد extract برای کانتینرهای مرتب‌شده و نامرتب، راه‌حلی کارآمد و ایمن برای این مسئله ارائه داده است . این متد، گره (Node) حاوی عنصر مورد نظر را از کانتینر جدا کرده و یک دسته‌ی گره (node_handle) بازمی‌گرداند که مالک آن عنصر است . در این فرآیند، هیچ عنصری کپی یا جابه‌جا نمی‌شود و تنها اشاره‌گرهای داخلی گره‌ها تغییر می‌کنند .

دسته‌ی گره (Node Handle) چیست؟

دسته‌ی گره، یک شیء از نوع انتقالی-فقط (Move-Only) است که مالکیت یک عنصر استخراج‌شده را در اختیار می‌گیرد . این شیء علاوه بر دسترسی به value_type عنصر، برای کانتینرهای map دو عضو کلیدی نیز دارد: متد key() که ارجاعی غیرثابت به کلید عنصر بازمی‌گرداند و متد mapped() که به مقدار نگاشت‌شده دسترسی می‌دهد . این قابلیت، امکان تغییر کلید را در حالی که عنصر از کانتینر جدا شده، فراهم می‌کند.

تغییر کلید بدون کپی در عمل

مراحل این عملیات بسیار ساده است. ابتدا گره مورد نظر با استفاده از extract و دادن کلید یا تکرارگر به آن استخراج می‌شود . سپس از طریق متد key() روی دسته‌ی گره، کلید را به مقدار جدید تغییر می‌دهیم . در نهایت، دسته‌ی گره را با استفاده از متد insert و std::move به کانتینر بازمی‌گردانیم . تمام این مراحل بدون هیچ کپی یا تخصیص مجدد حافظه انجام می‌شود و تنها عملیات تعادل‌سازی مجدد (در صورت نیاز) انجام می‌گیرد .

مزایای کلیدی نسبت به روش سنتی

بهبود عملکرد

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

حفظ اعتبار اشاره‌گرها و مراجع

هنگام استخراج یک گره، فقط تکرارگرهای مربوط به آن عنصر نامعتبر می‌شوند. اشاره‌گرها و مراجع به خود عنصر همچنان معتبر باقی می‌مانند، هرچند تا زمانی که عنصر در اختیار دسته‌ی گره است، نباید از آنها استفاده کرد. پس از درج مجدد عنصر در کانتینر، این اشاره‌گرها دوباره قابل‌استفاده می‌شوند .

انعطاف‌پذیری در انتقال بین کانتینرها

دسته‌های گره امکان انتقال عناصر بین کانتینرهای مختلف با کلید، مقدار و تخصیص‌دهنده‌ی یکسان را فراهم می‌کنند. برای مثال، می‌توان یک گره را از std::map استخراج و به std::multimap منتقل کرد .

ملاحظات مهم

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

کلیدواژه ها : std::map extract-تغییر کلید در map بدون کپی-C++17 node handle-استخراج گره در map-متد extract در C++17-دسته گره در C++-جابه‌جایی گره بین کانتینرها-node_handle key-مزایای extract نسبت به erase و insert-بهبود عملکرد map-انتقال عنصر بدون کپی-std::map extract example-آموزش node handle-مدیریت گره‌ها در C++-splicing در C++