เหตุใดอาร์กิวเมนต์ประเภทแผนที่ C ++ จึงต้องการตัวสร้างว่างเมื่อใช้ []


101

ดู รายการมาตรฐาน C ++ และประเภทที่สร้างได้ตามค่าเริ่มต้น

ไม่ใช่ปัญหาใหญ่น่ารำคาญเพราะฉันไม่ต้องการให้ชั้นเรียนของฉันถูกสร้างอินสแตนซ์โดยไม่มีข้อโต้แย้ง

#include <map>

struct MyClass
{
    MyClass(int t);
};

int main() {
    std::map<int, MyClass> myMap;
    myMap[14] = MyClass(42);
}

สิ่งนี้ทำให้ฉันมีข้อผิดพลาด g ++ ต่อไปนี้:

/usr/include/c++/4.3/bits/stl_map.h:419: ข้อผิดพลาด: ไม่มีฟังก์ชันที่ตรงกันสำหรับการเรียกไปที่ 'MyClass ()'

สิ่งนี้จะคอมไพล์ได้ดีถ้าฉันเพิ่มตัวสร้างเริ่มต้น ฉันแน่ใจว่ามันไม่ได้เกิดจากไวยากรณ์ที่ไม่ถูกต้อง


โค้ดด้านบนคอมไพล์ได้ดีบน MinGW (g ++ 3.4.5) และ MSVC ++ 2008 โดยมีเงื่อนไขว่าจะได้รับ typedef สำหรับ MyType และเซมิโคลอนต่อท้ายคลาส คุณต้องทำอย่างอื่น (เช่นโทรโอเปอเรเตอร์ [] ตามที่ bb กล่าวไว้) - โปรดโพสต์รหัสแบบเต็ม
j_random_hacker

ใช่คุณพูดถูก จะทำ.
Nick Bolton

ใช่โดยไม่ต้องใช้ myMap คุณจะไม่รู้ว่าต้องรวบรวมอะไรสำหรับคลาสแผนที่ ผู้ให้บริการไลบรารี stl และเวอร์ชันใดก็อาจช่วยได้เช่นกัน
Greg Domjan

คำตอบ:


168

ปัญหานี้มาพร้อมกับตัวดำเนินการ [] อ้างจากเอกสาร SGI:

data_type& operator[](const key_type& k)- ส่งคืนการอ้างอิงไปยังออบเจ็กต์ที่เชื่อมโยงกับคีย์เฉพาะ หากแผนที่ไม่ได้แล้วมีวัตถุดังกล่าวแทรกวัตถุเริ่มต้นoperator[] data_type()

หากคุณไม่มีตัวสร้างเริ่มต้นคุณสามารถใช้ฟังก์ชันแทรก / ค้นหา ตัวอย่างต่อไปนี้ใช้งานได้ดี:

myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;

11
คำตอบที่ดีเยี่ยม - โน้ตยังemplaceใน C ++ 11 insertเป็นทางเลือกที่จะรวบรัด
prideout

3
เหตุใดจึงstd::<map>::value_typeมีการinsertโทร
thomthom

1
เหตุใดตัวสร้างเริ่มต้นจึงต้องกำหนดโดยผู้ใช้
schuess

@schuess ฉันไม่เห็นเหตุผลว่าทำไมถึงเป็นเช่นนั้น= defaultควรทำงานได้ดี
underscore_d

เงื่อนไข 'แผนที่ไม่มีวัตถุดังกล่าว' จะได้รับการประเมินที่รันไทม์ ทำไมเวลาคอมไพล์ผิดพลาด?
Gaurav Singh

7

ใช่. ค่าในคอนเทนเนอร์ STL จำเป็นต้องรักษาความหมายของการคัดลอก IOW พวกเขาจำเป็นต้องทำงานเหมือนประเภทดั้งเดิม (เช่น int) ซึ่งหมายความว่าเหนือสิ่งอื่นใดพวกเขาควรเป็นค่าเริ่มต้นที่สร้างได้

หากไม่มีสิ่งนี้ (และข้อกำหนดอื่น ๆ ) การดำเนินการคัดลอก / ย้าย / สลับ / เปรียบเทียบภายในโครงสร้างข้อมูลที่ใช้คอนเทนเนอร์ STL จะเป็นเรื่องยากโดยไม่จำเป็น

เมื่ออ้างอิงถึงมาตรฐาน C ++ ฉันเห็นว่าคำตอบของฉันไม่ถูกต้อง ในความเป็นจริงแล้วโครงสร้างเริ่มต้นไม่ใช่ข้อกำหนด :

จาก 20.1.4.1:

ไม่จำเป็นต้องใช้ตัวสร้างเริ่มต้น ลายเซ็นฟังก์ชันสมาชิกคลาสคอนเทนเนอร์บางตัวระบุตัวสร้างเริ่มต้นเป็นอาร์กิวเมนต์เริ่มต้น T () ต้องเป็นนิพจน์ที่กำหนดไว้อย่างชัดเจน ...

ดังนั้นกล่าวอย่างชัดเจนประเภทค่าของคุณจะต้องเป็นค่าเริ่มต้นที่สามารถสร้างได้หากคุณบังเอิญใช้ฟังก์ชันของคอนเทนเนอร์ที่ใช้ตัวสร้างเริ่มต้นในลายเซ็น

ข้อกำหนดที่แท้จริง (23.1.3) จากค่าทั้งหมดที่จัดเก็บในคอนเทนเนอร์ STL คือCopyConstructibleและAssignableและ

นอกจากนี้ยังมีข้อกำหนดเฉพาะอื่น ๆ สำหรับตู้คอนเทนเนอร์โดยเฉพาะเช่นการเป็นComparable(เช่นกุญแจในแผนที่)


อนึ่งการคอมไพล์ต่อไปนี้โดยไม่มีข้อผิดพลาดบน comeau :

#include <map>

class MyClass
{
public:
    MyClass(int t);
};

int main()
{
    std::map<int, MyClass> myMap;
}

นี่อาจเป็นปัญหา g ++


2
คุณคิดว่า bb อาจเกี่ยวข้องกับ [] operator หรือไม่?
Nick Bolton

13
รหัสนั้นอาจรวบรวมเนื่องจากคุณไม่ได้เรียก myMap []
jfritz42

4

ตรวจสอบข้อกำหนดประเภทที่จัดเก็บของ stl :: map คอลเลกชัน stl จำนวนมากต้องการให้ชนิดที่จัดเก็บมีคุณสมบัติเฉพาะบางอย่าง (ตัวสร้างเริ่มต้นตัวสร้างการคัดลอก ฯลฯ )

stl :: map ต้องการตัวสร้างที่ไม่มีอาร์กิวเมนต์เนื่องจากมันถูกใช้เมื่อตัวดำเนินการ [] ถูกเรียกใช้ด้วยคีย์ซึ่งแผนที่ยังไม่ได้เก็บไว้ ในกรณีนี้ตัวดำเนินการ [] จะแทรกรายการใหม่ซึ่งประกอบด้วยคีย์และค่าใหม่ที่สร้างโดยใช้ตัวสร้างแบบไม่มีพารามิเตอร์ และค่าใหม่นี้จะถูกส่งกลับ


-2

ตรวจสอบว่า:

  • คุณลืม ';' หลังการประกาศชั้นเรียน
  • MyType ควรได้รับการประกาศตามนั้น
  • ไม่มีตัวสร้างเริ่มต้นที่นั่น ...

ฉันคิดว่าการประกาศมาตรฐาน :: แผนที่ดูเหมือนถูกต้อง


คอมไพล์ได้ดีถ้าฉันเพิ่มตัวสร้างเริ่มต้น
Nick Bolton

-2

เป็นไปได้มากที่สุดเพราะ std :: pair ต้องการมัน std :: pair เก็บค่าสองค่าโดยใช้ความหมายของค่าดังนั้นคุณต้องสามารถสร้างอินสแตนซ์ได้โดยไม่ต้องมีพารามิเตอร์ ดังนั้นรหัสจึงใช้ std :: pair ในที่ต่างๆเพื่อคืนค่าแผนที่ให้กับผู้เรียกและโดยทั่วไปจะทำได้โดยการสร้างอินสแตนซ์คู่ว่างและกำหนดค่าลงในนั้นก่อนที่จะส่งคืนคู่โลคัล

คุณสามารถแก้ไขสิ่งนี้ได้ด้วยตัวชี้อัจฉริยะโดยใช้แผนที่ <int, smartptr <MyClass>> แต่จะเพิ่มค่าใช้จ่ายในการตรวจหาพอยน์เตอร์ว่าง


2
+0. คู่ <T, U> สามารถใช้ได้ดีกับประเภท T และ U ที่ไม่มีตัวสร้างเริ่มต้น - สิ่งเดียวที่ไม่สามารถใช้ในกรณีนี้คือตัวสร้างเริ่มต้นของคู่ <T, U> ไม่มีการนำแผนที่ <K, V> คุณภาพดีมาใช้จะใช้ตัวสร้างเริ่มต้นนี้เพราะมัน จำกัด สิ่งที่ K และ V สามารถเป็นได้
j_random_hacker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.