[]を使用するときにC ++のマップタイプ引数に空のコンストラクターが必要なのはなぜですか?


98

C ++標準リストとdefault-constructible型も参照してください

大きな問題ではありません。特定の引数なしでクラスをインスタンス化したくないので、迷惑です。

#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で問題なくコンパイルされます。ただし、MyTypeのtypedefが指定され、クラスの最後にセミコロンが追加されている必要があります。あなたは何か他のことをしている必要があります(例えばbbによって言及されたようにoperator []を呼び出す)- 完全なコードを投稿してください。
j_random_hacker 2009年

ああ、そうです。しましょう。
ニックボルトン

ええ、myMapを使用しないと、マップクラス用に何をコンパイルする必要があるかわかりません。どのstlライブラリプロバイダーとバージョンも役立つ場合があります。
Greg Domjan 2009年

回答:


165

この問題はoperator []で発生します。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
プライドアウト2014年

3
なぜそれstd::<map>::value_typeinsert電話に出ているのですか?
thomthom

1
デフォルトのコンストラクタをユーザー定義する必要があるのはなぜですか?
2015年

@schuess私がそれをする理由はわかりません:= defaultうまくいくはずです。
underscore_d 2016年

「マップにそのようなオブジェクトがまだ含まれていない」という条件は、実行時に評価されます。なぜコンパイル時エラー?
Gaurav Singh

8

はい。STLコンテナーの値は、コピーのセマンティクスを維持する必要があります。IOW、それらはプリミティブ型(たとえば、int)のように動作する必要があります。これは、とりわけ、デフォルトで構築可能であることを意味します。

これ(およびその他の要件)がないと、STLコンテナーが実装されているデータ構造に、さまざまな内部のコピー/移動/スワップ/比較操作を実装することが不必要に困難になります。

C ++標準を参照すると、私の答えが正確ではないことがわかりました。デフォルトの構築は、実際には要件ではありません

20.1.4.1以降:

デフォルトのコンストラクタは必要ありません。特定のコンテナークラスメンバー関数のシグネチャは、既定のコンストラクターを既定の引数として指定します。T()は明確に定義された式でなければなりません...

したがって、厳密に言うと、値の型は、シグネチャでデフォルトのコンストラクタを使用するコンテナの関数をたまたま使用している場合にのみ、デフォルトで構成可能である必要があります。

STLコンテナに保存されているすべての値の実際の要件(23.1.3)はCopyConstructible、およびAssignableです。

特定のコンテナには、存在するComparable(マップ内のキーなど)などの他の特定の要件もあります。


ちなみに、次のコードはcomeauでエラーなしでコンパイルされます

#include <map>

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

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

したがって、これはg ++の問題である可能性があります。


2
あなたはbbが[]演算子に関して何かをしていると思いますか?
ニックボルトン

12
myMap []を呼び出さないため、このコードはおそらくコンパイルされます
jfritz42

3

stl :: mapの保管タイプの要件を確認してください。多くのstlコレクションでは、格納された型に特定のプロパティ(デフォルトコンストラクター、コピーコンストラクターなど)が含まれている必要があります。

stl :: mapでは、引数なしのコンストラクタが必要です。これは、operator []がマップでまだ保持されていないキーで呼び出されたときに使用されるためです。この場合、operator []は、パラメーターなしのコンストラクターを使用して構築された新しいキーと値で構成される新しいエントリを挿入します。そして、この新しい値が返されます。


-2

次のことを確認します。

  • 「;」を忘れた クラス宣言の後。
  • MyTypeはそれに応じて宣言されている必要があります。
  • デフォルトのコンストラクタはありません...

std :: map宣言は正しいように思えます。


デフォルトのコンストラクターを追加すると問題なくコンパイルされます。
ニックボルトン

-2

std :: pairが必要とするためです。std :: pairは、値のセマンティクスを使用して2つの値を保持するため、パラメーターなしでそれらをインスタンス化できる必要があります。したがって、コードはさまざまな場所でstd :: pairを使用して呼び出し元にマップ値を返します。これは通常、ローカルペアを返す前に空のペアをインスタンス化して値を割り当てることで行われます。

map <int、smartptr <MyClass>>を使用してスマートポインターでこれを回避することができますが、これによりnullポインターをチェックするオーバーヘッドが追加されます。


2
+0。pair <T、U>は、T型とU型のデフォルトコンストラクタがない場合でも問題なく使用できます。この場合に使用できないのは、pair <T、U>自体のデフォルトコンストラクタのみです。map <K、V>のまともな品質の実装では、KおよびVが何であるかを制限するため、このデフォルトのコンストラクターを使用しません。
j_random_hacker 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.