Каков наилучший способ удалить карту входа <int, A *> - PullRequest
2 голосов
/ 28 марта 2011

Я обсуждал со своим коллегой, как удалить запись на карте, в которой в качестве индекса указывается int, а указатель указывает на объект.

Я сказал, сначала отпустите объект, а затем удалите запись.Мой коллега сказал, сначала удалите запись, а затем отпустите объект.

Так что же лучше?Любой трюк на этот вопрос?

Ответы [ 6 ]

5 голосов
/ 28 марта 2011

Сначала удалите объект, затем удалите с карты.В противном случае вы просто вводите бессмысленную промежуточную переменную для хранения указателя.Пока вы однопоточны или имеете правильную блокировку в многопоточном сценарии, оба метода для всех практических целей эквивалентны.

map<int, A *>::iterator it = mymap.find(1);
if (it != mymap.end()) {
  delete it->second;
  mymap.erase(it);
} 
3 голосов
/ 28 марта 2011

Если у вас нет многопоточной среды, любой из них будет работать. Практическое правило заключается в том, что после возврата вашей функции не должно быть висящих указателей , т.е. никаких указателей на только что удаленный объект.

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

1 голос
/ 28 марта 2011

Консервативный подход - сначала стереть, а затем удалить указатель.

Хранение неверного значения указателя в стандартном контейнере может привести к неопределенному поведению, по крайней мере, в соответствии с общей интерпретацией параграфа стандарта C ++ [basic.stc.dynamic.deallocation] / 4 , который запрещает любое использование недопустимых значений указателя (например, контейнер, создающий копию указателя внутри), и [lib.container.requirements] , который предписывает, что объекты хранятся вконтейнеры должны быть CopyConstructible и Назначаемые .

Однако проблема несколько спорная.

1 голос
/ 28 марта 2011

Вдохновленный @Nim, как насчет третьего способа: сохранять объекты на карте по значению или по умному указателю.Тогда RAII автоматически позаботится обо всей очистке для вас!

Если вы должны использовать необработанные указатели, это не имеет большого значения, если вы убедитесь, что применена любая необходимая блокировка для потоков.

0 голосов
/ 28 марта 2011

Вы должны изучить использование ptr_map из boost.У вас нет оснований свернуть свое собственное решение для этого.Слушайте всех, кто указывает на предостережения с многопоточным доступом к вашим контейнерам.

0 голосов
/ 28 марта 2011

Это, вероятно, не имеет значения.

Вы можете подумать, что это будет иметь значение, если у вас есть два потока: один пытается удалить элемент с карты, а другой пытается получить доступ к той же карте.Вы можете прийти к выводу, что было бы безопаснее сначала удалить элемент с карты, чтобы другой поток не получил указатель на удаленный объект.

Однако, если у вас есть несколько потоков, обращающихсяту же карту, вам нужно защитить ее с помощью объекта синхронизации (мьютекс или CRITICAL_SECTION, если вы работаете в простом Win32.) std :: map не безопасен для несинхронизированного многопоточного использования, когда один поток изменяет коллекцию.Итак, если вы уже блокируете карту во время удаления и удаления, не имеет значения, каким образом вы это делаете.

Сказав это, если уничтожение вашего объекта занимает много времени, вы можетекак переместить вызов удаления за пределы части кода, заблокированной мьютексом.В этом случае сначала сохраните указатель объекта во временной переменной, удалите его запись на карте, разблокируйте, а затем удалите.

...