Mengapa argumen tipe peta C ++ memerlukan konstruktor kosong saat menggunakan []?

99

Lihat juga daftar standar C ++ dan tipe yang dapat dibangun secara default

Bukan masalah besar, hanya menjengkelkan karena saya tidak ingin kelas saya dibuat tanpa argumen tertentu.

#include <map>

struct MyClass
{
    MyClass(int t);
};

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

Ini memberi saya kesalahan g ++ berikut:

/usr/include/c++/4.3/bits/stl_map.h:419: error: tidak ada fungsi yang cocok untuk panggilan ke 'MyClass ()'

Ini mengkompilasi dengan baik jika saya menambahkan konstruktor default; Saya yakin itu tidak disebabkan oleh sintaks yang salah.

Nick Bolton
sumber
Kode di atas dapat dikompilasi dengan baik pada MinGW (g ++ 3.4.5) dan MSVC ++ 2008, asalkan typedef untuk MyType diberikan dan titik koma ditambahkan ke akhir kelas. Anda harus melakukan sesuatu yang lain (mis. Menelepon operator [] seperti yang disebutkan oleh bb) - harap posting kode lengkapnya .
j_random_hacker
Ah, ya, kamu benar. Akan melakukan.
Nick Bolton
Ya, tanpa penggunaan myMap Anda tidak tahu apa yang perlu dikompilasi untuk kelas peta. Penyedia perpustakaan stl dan versi mana juga yang mungkin juga membantu.
Greg Domjan

Jawaban:

165

Masalah ini datang dengan operator []. Kutipan dari dokumentasi SGI:

data_type& operator[](const key_type& k)- Mengembalikan referensi ke objek yang dikaitkan dengan kunci tertentu. Jika peta belum berisi objek seperti itu, operator[] masukkan objek default data_type().

Jika Anda tidak memiliki konstruktor default, Anda dapat menggunakan fungsi sisipkan / temukan. Contoh berikut berfungsi dengan baik:

myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;
bayda
sumber
11
Jawaban yang sangat bagus - perhatikan juga emplacedalam C ++ 11 sebagai alternatif singkat untuk insert.
Prideout
3
Mengapa itu std::<map>::value_typeada di inserttelepon?
thomthom
1
Mengapa konstruktor default perlu ditentukan pengguna?
schuess
@schuess Saya tidak melihat alasan mengapa itu terjadi: = defaultseharusnya bekerja dengan baik.
underscore_d
Kondisi 'Peta tidak berisi objek seperti itu' akan dievaluasi saat runtime. Mengapa terjadi kesalahan waktu kompilasi?
Gaurav Singh
7

Iya. Nilai dalam penampung STL perlu mempertahankan semantik salinan. IOW, mereka perlu berperilaku seperti tipe primitif (misalnya int) yang berarti, antara lain, mereka harus dapat dibangun secara default.

Tanpa ini (dan persyaratan lainnya), akan sulit untuk mengimplementasikan berbagai operasi salin / pindahkan / tukar / bandingkan internal pada struktur data yang digunakan container STL.

Setelah mengacu pada Standar C ++, saya melihat jawaban saya tidak akurat. Konstruksi default, pada kenyataannya, bukanlah suatu persyaratan :

Dari 20.1.4.1:

Konstruktor default tidak diperlukan. Tanda tangan fungsi anggota kelas kontainer tertentu menentukan konstruktor default sebagai argumen default. T () harus merupakan ekspresi yang terdefinisi dengan baik ...

Jadi, tegasnya, jenis nilai Anda hanya perlu dapat dibangun secara default jika Anda kebetulan menggunakan fungsi penampung yang menggunakan konstruktor default dalam tanda tangannya.

Persyaratan sebenarnya (23.1.3) dari semua nilai yang disimpan dalam wadah STL adalah CopyConstructibledan Assignable.

Ada juga persyaratan khusus lainnya untuk wadah tertentu, seperti keberadaan Comparable(misalnya untuk kunci di peta).


Kebetulan, berikut ini mengkompilasi tanpa kesalahan pada hasil :

#include <map>

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

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

Jadi ini mungkin masalah g ++.

Assaf Lavie
sumber
2
Apakah menurut Anda bb bisa mengarah ke sesuatu tentang operator []?
Nick Bolton
13
Kode itu mungkin terkompilasi karena Anda tidak memanggil myMap []
jfritz42
3

Periksa persyaratan tipe yang disimpan dari stl :: map. Banyak koleksi stl mengharuskan tipe yang disimpan berisi beberapa properti tertentu (konstruktor default, konstruktor salinan, dll.).

Konstruktor tanpa argumen dibutuhkan oleh stl :: map, karena ini digunakan, saat operator [] dipanggil dengan kunci, yang belum disimpan oleh peta. Dalam hal ini operator [] menyisipkan entri baru yang terdiri dari kunci baru dan nilai yang dibuat menggunakan konstruktor tanpa parameter. Dan nilai baru ini kemudian dikembalikan.

oo_olo_oo
sumber
-2

Periksa apakah:

  • Anda lupa ';' setelah deklarasi kelas.
  • MyType seharusnya dinyatakan sesuai.
  • Tidak ada konstruktor default di sana ...

Deklarasi std :: map tampaknya benar, saya kira.

Hernán
sumber
Mengompilasi dengan baik jika saya menambahkan konstruktor default.
Nick Bolton
-2

Kemungkinan besar karena std :: pair membutuhkannya. std :: pair menyimpan dua nilai menggunakan semantik nilai sehingga Anda harus dapat membuatnya tanpa parameter. Jadi kode ini menggunakan std :: pair di berbagai tempat untuk mengembalikan nilai peta ke pemanggil dan ini biasanya dilakukan dengan membuat instance pasangan kosong dan menetapkan nilai ke dalamnya sebelum mengembalikan pasangan lokal.

Anda bisa menyiasati ini dengan penunjuk cerdas menggunakan peta <int, smartptr <MyClass>> tetapi itu menambahkan overhead pemeriksaan penunjuk nol.

jmucchiello.dll
sumber
2
+0. pair <T, U> dapat digunakan dengan baik dengan tipe T dan U tidak memiliki konstruktor default - satu-satunya hal yang tidak dapat digunakan dalam kasus ini adalah konstruktor default pair <T, U> sendiri. Tidak ada implementasi peta <K, V> dengan kualitas yang layak yang akan menggunakan konstruktor default ini karena membatasi apa yang bisa K dan V.
j_random_hacker