Почему аргумент типа карты С++ требует пустого конструктора при использовании []?

См. Также 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()

Это прекрасно скомпилируется, если я добавлю конструктор по умолчанию; Я уверен, что это не вызвано неправильным синтаксисом.

Ответ 1

Эта проблема связана с оператором []. Цитата из документации SGI:

data_type& operator[](const key_type& k) - возвращает ссылку на объект что связано с конкретным ключ. Если карта еще не содержат такой объект, operator[]вставляет объект по умолчанию data_type().

Если у вас нет конструктора по умолчанию, вы можете использовать функции insert/find. Следующий пример отлично работает:

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

Ответ 2

Да. Значения в STL-контейнерах должны содержать семантику копирования. IOW, они должны вести себя как примитивные типы (например, int), что, между прочим, должно быть конструктивным по умолчанию.

Без этого (и других требований) было бы бесполезно реализовать различные внутренние операции копирования/перемещения/замены/сравнения в структурах данных, с которыми реализованы контейнеры STL. Забастовкa >

После ссылки на стандарт С++, я вижу, что мой ответ не был точным. Конструкция по умолчанию, по сути, не является обязательным требованием:

Из 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++.

Ответ 3

Проверьте требования сохраненного типа stl:: map. Многие коллекции stl требуют, чтобы хранимый тип содержал определенные свойства (конструктор по умолчанию, конструктор копирования и т.д.).

Конструктор без аргументов необходим stl:: map, потому что он использовался, когда оператор [] вызывается с ключом, который еще не был сохранен картой. В этом случае оператор [] вставляет новую запись, состоящую из нового ключа и значения, построенного с использованием конструктора без параметров. И это новое значение будет возвращено.

Ответ 4

Убедитесь, что:

  • Вы забыли ';' после объявления класса.
  • MyType должен быть объявлен соответствующим образом.
  • Нет конструктора по умолчанию там...

Я думаю, что утверждение std:: map кажется правильным.

Ответ 5

Скорее всего потому, что это требует std:: pair. std:: pair имеет два значения, используя семантику значения, поэтому вы должны иметь возможность создавать их без параметров. Таким образом, код использует std:: pair в разных местах, чтобы вернуть значения карты вызывающему, и это обычно делается путем создания пустых пар и назначения значений в нем перед возвратом локальной пары.

Вы можете обойти это с помощью интеллектуальных указателей, используя карту < int, smartptr < MyClass → , но это добавляет накладные расходы на проверку нулевых указателей.