map <int, int> значення за замовчуванням


78
std::map<int,int> mapy;
++mapy[5];

Чи можна припустити, що mapy[5]завжди буде 1? Я маю на увазі, mapy[5]завжди буде отримувати значення за замовчуванням 0 перед '++', навіть якщо це явно не оголошено, як у моєму коді?



3
@bobobobo: це питання старіше за значення std :: map за замовчуванням для вбудованого типу , тоді дублікат має бути std :: map за замовчуванням для вбудованого типу .
mpromonet

Відповіді:


124

Як тільки ви отримуєте доступ до карти за допомогою оператора [], якщо ключ не існує, він додається. Викликається ініціалізатор за замовчуванням типу int - тому він отримає значення 0.


Наскільки я переконався, intпочаткове значення неініціалізованого примітиву невизначене - тобто воно може бути 0 або може бути -99765521. У вас коли-небудь було неініціалізовано intяк змінну класу і чи мало одне з цих шалених значень у вашій програмі? Тим не менш, я перевірив це, і, здається, це працює. #include <stdio.h> #include <map> using namespace std; int main() { map<int,int> m ; for( int i = 0 ; i < 100 ; i++ ) m[i]++ ; for( const pair<int,int>& p : m ) printf( "m[%d] => %d\n", p.first, p.second ) ; }
bobobobo 02

29
Це працює не так, як ви думаєте. int x; змушує x отримати невизначене значення int x = int (); Знову x отримує 0 клас foo {int x; foo (): x () {}}; foo f; Тут fx буде нульовим
rep_movsd

@bobobobo: Дивись мою відповідь. Ініціалізація є більш складною і має безліч "режимів роботи" залежно від контексту.
Гонки легкості на орбіті

Я думав, що значення у всіх контейнерах створюються в кучі, і значення в купі буде ініціалізоване відповідним значенням. У цьому випадку 0. Чи правильно?
r0ng

1
У C ++ куча і пам'ять стека неініціалізовані - об'єкт ініціалізується за допомогою конструктора за замовчуванням - мова має конструктори за замовчуванням для примітивних типів, які ініціалізують їх до 0, коли ви викликаєте його правильно, див. Мій попередній коментар
rep_movsd,

40

Так, можна з упевненістю припустити.

Карти operator[]вказані таким чином: ([map.access])

Ефекти: Якщо xна карті немає ключа, еквівалентного тому, вставляється value_type(std::move(x), T())на карту.
Повертає: Посилання на mapped_typeвідповідне xв *this.

T()використовує ініціалізацію значення для всіх, Tкрім void ([expr.type.conv] / 2) , а ініціалізацію значення для примітиву призводить до нульової ініціалізації ([dcl.init] / 7) .

Тому вираз обчислюється як посилання на об'єкт із нульовим значенням ([dcl.init] / 5) .

Потім operator++виклик збільшує цей об’єкт до одного і оцінює до одного.

(Усі посилання на C ++ 11.)


2
Поняття не маю, чому вашу відповідь проголосували проти, оскільки ви правильні. Це саме те, що сказано в специфікації (просто перевірив це сам).
Ганс де Руйтер,

9

Так, значення за замовчуванням буде типовим для цього типу. Якщо вам потрібен інший за замовчуванням, ви можете створити клас, який поводиться як int, але має інший конструктор за замовчуванням.


7

Відповідь Rep_Movsd занадто спрощена і, ймовірно, призведе до численних надзвичайно небезпечних помилок. Примітивні типи даних у C ++ не мають ініціалізаторів. Луї Бренді провів чудову бесіду, в якій обговорив багато типових помилок C ++, допущених у Facebook, і нерозуміння того, як працює std :: map <> [], було однією з помилок, які він обговорював, це чудовий ресурс, хоча він цього не робить детально дізнатись, як насправді працює std :: map <> [].

Загалом, ints не ініціалізуються і невизначені, як і всі примітивні типи. Сказано, що при використанні зі std :: map <> [] int має за замовчуванням значення нуля, встановлене за допомогою процесу, який називається ініціалізацією значення. Ініціалізація значення - це процес, який насправді працює зі структурами загалом. Наприклад,

struct Struct {
Struct() : memberVariable() {}
       int memberVariable;
};

Завжди ініціалізує int до нуля. Якби змінні-члени були іншими примітивними типами, вони також мали б конкретні значення ініціалізації. Наприклад, наступні типи ініціалізуються через ініціалізацію значень так:

bool = false
float = 0.0f
enum = (тип переліку ) 0
покажчик = нульовий покажчик
покажчика на member = нульовий покажчик члена

Будьте гранично обережні при роботі з даними, які не є явно ініціалізованими. Останнє, розглянемо наступний код

map<string, int> myMap;
cout << myMap["Foo"];

Цей код не тільки завжди ініціалізує ціле число до 0, але він також вставить 0 на карту. Просто для швидкого підсумовування примітивні типи даних невизначені, якщо не ініціалізовані, але в деяких випадках, наприклад, зі структурою або значенням карти, ініціалізація ініціалізує примітивні дані з певним значенням.


2
"Примітивні типи даних у C ++ не мають ініціалізаторів" Це занадто спрощено і, ймовірно, призведе до небезпечних помилок. "не ініціалізовано" Ні. Ну, не зовсім. Це називається ініціалізацією за замовчуванням, але так, результат є невизначеним значенням (C ++ 11 8.5 / 11). "невизначені" Ні. Невизначено. "structs" C ++ не має структур. "ініціалізація значення" Правильна. Ключовим моментом є різний тип використовуваної ініціалізації. Також у вашій прозі є кілька з’єднань комами.
Гонки легкості на орбіті

Типові типи даних не ініціалізуються до будь-якого значення за замовчуванням. Вони не мають конструкції за замовчуванням. Вони, в деяких випадках, мають ціннісну конструкцію. Розрізнення, яке ви намагаєтеся провести між невизначеною та невизначеною поведінкою, є абсурдним. Відповідно до стандарту C ++ 11 невизначена поведінка визначається як: "... непереносима або помилкова конструкція програми або помилкові дані, для яких цей міжнародний стандарт не вимагає вимог", по суті, означає помилку в будь-якій логіці або стані, і результат невідомо. Я ніколи не говорив, що структури були з C ++.
Рейчел Кейсі,

"Різниця, яку ви намагаєтеся провести між невизначеною та невизначеною поведінкою, є абсурдною". Я не робив різниці, стандарт робив. Якщо ви вважаєте це недоречним, ви, звичайно, можете висловити заперечення у списку розсилки робочої групи ISO.
Гонки легкості на орбіті

"Я ніколи не говорив, що структури були з C ++." Якщо ви це вже знаєте, то чому ви говорили про структури на запитання на C ++? Тепер це недоречно!
Гонки легкості на орбіті

1
Ні. Неможливо створити структуру в C ++. Створити клас можливо лише за допомогою успадкованого structключового слова. Код, який ви показали, містить клас . С ++ не має конструкцій. Подальше читання: stackoverflow.com/a/36917400/560648 stackoverflow.com/a/34108140/560648
Гонки легкості на орбіті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.