std :: unordered_map โอเปอเรเตอร์ [] ทำการ zero-initialization สำหรับคีย์ที่ไม่มีอยู่หรือไม่?


25

ตาม cppreference.com std::map::operator[]สำหรับค่าที่ไม่ได้มีอยู่จะเริ่มต้นเป็นศูนย์

อย่างไรก็ตามไซต์เดียวกันไม่ได้กล่าวถึงการกำหนดค่าเริ่มต้นเป็นศูนย์std::unordered_map::operator[]ยกเว้นจะมีตัวอย่างที่ต้องใช้สิ่งนี้

แน่นอนว่านี่เป็นเพียงเว็บไซต์อ้างอิงไม่ใช่มาตรฐาน ดังนั้นรหัสด้านล่างตกลงหรือไม่?

#include <unordered_map>
int main() {
    std::unordered_map<int, int> map;
    return map[42];     // is this guaranteed to return 0?
}

13
@ Ælexคุณไม่สามารถทดสอบได้อย่างน่าเชื่อถือหากมีสิ่งใดเริ่มต้น
idclev 463035818

2
@ Ælexฉันไม่เข้าใจจริง ๆ คุณจะมีการเริ่มต้นstd::optionalไม่ได้อย่างไร
idclev 463035818

2
@ Ælexไม่มีวิธีที่จะทดสอบว่าวัตถุนั้นถูกเตรียมใช้งานหรือไม่เนื่องจากการดำเนินการใด ๆ บนวัตถุที่ไม่ได้กำหนดค่าเริ่มต้นนอกเหนือจากการเตรียมใช้งานส่งผลให้เกิดพฤติกรรมที่ไม่ได้กำหนด std::optionalวัตถุที่ถือไม่มีค่าที่มีอยู่ยังคงเป็นวัตถุที่เริ่ม
bolov

2
วัตถุค่าเป็นค่าเริ่มต้นไม่เป็นศูนย์เริ่มต้น สำหรับประเภทสเกลาร์สิ่งเหล่านี้เหมือนกัน แต่สำหรับประเภทชั้นเรียนนั้นแตกต่างกัน
aschepler

@bolov ฉันพยายามทดสอบเมื่อวานนี้โดยใช้ gnu 17 และ std 17 และที่แปลกประหลาดที่สุดที่ฉันได้รับคือ initialisation ศูนย์ ฉันคิดว่าstd::optional has_valueจะทดสอบ แต่ล้มเหลวดังนั้นฉันจึงเดาว่าคุณถูกต้อง
Ælex

คำตอบ:


13

ขึ้นอยู่กับสิ่งที่เกินพิกัดที่เรากำลังพูดถึงstd::unordered_map::operator[]เทียบเท่ากับ[unord.map.elem]

T& operator[](const key_type& k)
{
    return try_­emplace(k).first->second;
}

(การโอเวอร์โหลดที่มีการอ้างอิงค่า rvalue เพียงแค่ย้ายkเข้าไปtry_emplaceและเหมือนกัน)

หากเป็นองค์ประกอบที่มีอยู่ภายใต้คีย์kในแผนที่แล้วtry_emplaceส่งกลับ iterator falseองค์ประกอบที่และ มิฉะนั้นtry_emplaceแทรกองค์ประกอบใหม่ภายใต้คีย์kและส่งกลับ iterator ไปที่และtrue [unord.map.modifiers] :

template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);

สิ่งที่น่าสนใจสำหรับเราคือกรณีที่ไม่มีองค์ประกอบ[unord.map.modifiers] / 6 :

มิฉะนั้นแทรกวัตถุประเภทvalue_­typeสร้างด้วยpiecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...)

(การโอเวอร์โหลดที่ใช้การอ้างอิงค่า rvalue เพิ่งจะย้ายkไปforward_­as_­tupleและอีกครั้งก็เหมือนกัน)

เนื่องจากvalue_typeเป็นpair<const Key, T> [unord.map.overview] / 2สิ่งนี้บอกเราว่าองค์ประกอบแผนที่ใหม่จะถูกสร้างขึ้นเป็น:

pair<const Key, T>(piecewise_­construct, forward_­as_­tuple(k), forward_­as_­tuple(std​::​forward<Args>(args)...));

เนื่องจากargsว่างเปล่าเมื่อมาจากoperator[]สิ่งนี้จะทำให้ค่าใหม่ของเราถูกสร้างขึ้นในฐานะสมาชิกของpairไม่มีข้อโต้แย้ง[pairs.pair] / 14ซึ่งเป็นการเริ่มต้นโดยตรง[class.base.init] / 7ของประเภทค่าที่Tใช้()เป็นค่าเริ่มต้นที่เดือดลงไปเริ่มต้นค่า[dcl.init] /17.4 เริ่มต้นค่าของintเป็นศูนย์เริ่มต้น[dcl.init] / 8 และศูนย์การเริ่มต้นของintธรรมชาติเริ่มต้นที่int0 [dcl.init] / 6

ใช่รหัสของคุณรับประกันว่าจะส่งคืน 0 ...


21

ในเว็บไซต์ที่คุณเชื่อมโยงมันบอกว่า:

เมื่อมีการใช้ตัวจัดสรรเริ่มต้นผลลัพธ์นี้ในคีย์ที่กำลังคัดลอกที่สร้างจากคีย์และค่าที่แมปจะถูกกำหนดค่าเริ่มต้น

ดังนั้นจึงintเป็นค่าเริ่มต้น :

ผลกระทบของการกำหนดค่าเริ่มต้นคือ:

[ ... ]

4) มิฉะนั้นวัตถุจะถูกคืนค่าเป็นศูนย์

0นี่คือเหตุผลที่ผลที่ได้คือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.